diff --git a/.github/workflows/Nuke.yml b/.github/workflows/Nuke.yml index 3c342fe6b..e69f8597d 100644 --- a/.github/workflows/Nuke.yml +++ b/.github/workflows/Nuke.yml @@ -1,7 +1,13 @@ name: Nuke + on: - pull_request: push: + branches: + - 'master' + - 'dev' + pull_request: + branches: + - 'dev' jobs: windows: diff --git a/.github/workflows/Qodana.yml b/.github/workflows/Qodana.yml.disabled similarity index 100% rename from .github/workflows/Qodana.yml rename to .github/workflows/Qodana.yml.disabled diff --git a/Contributing.md b/Contributing.md index 0f6803b95..a5aea1432 100644 --- a/Contributing.md +++ b/Contributing.md @@ -116,12 +116,13 @@ To execute NUKE build on GitHub, you can follow these steps: | Folder | Description | |----------|----------------------------------------------------------------------------| +| branding | Source files for logo, banner, installer background | +| history | Museum, storage of original RevitLookup documentation | | build | Nuke build system. Used to automate project builds | | install | Add-in installer, called implicitly by the Nuke build | | source | Project source code folder. Contains all solution projects | +| tools | Extra tools for RevitLookup development | | output | Folder of generated files by the build system, such as bundles, installers | -| branding | Source files for logo, banner, installer background | -| doc | Museum, storage of original RevitLookup documentation | ## Project structure diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..6b2b2a4fb --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,32 @@ + + + + + enable + latest + x64 + true + + + + 2021 + net48 + + + 2022 + net48 + + + 2023 + net48 + + + 2024 + net48 + + + 2025 + net8.0-windows + + + \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..101633349 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,74 @@ + + + + + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RevitLookup.sln b/RevitLookup.sln index 42ff0e5dd..a833c4e6f 100644 --- a/RevitLookup.sln +++ b/RevitLookup.sln @@ -1,160 +1,399 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{374DC381-78CC-4FC7-A566-EB8C71C6369F}" - ProjectSection(SolutionItems) = preProject - Readme.md = Readme.md - Changelog.md = Changelog.md - Contributing.md = Contributing.md - Build\Build.Configuration.cs = Build\Build.Configuration.cs - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Installer", "install\Installer.csproj", "{B3814652-9158-4056-A721-1A380DE74BAE}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "build\Build.csproj", "{64D9C223-D070-46CD-A635-04FD4E1BEC3C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RevitLookup", "source\RevitLookup\RevitLookup.csproj", "{05C77115-2277-4DFC-8F95-BE37E5F1130F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI", "source\RevitLookup.UI\RevitLookup.UI.csproj", "{CE5C104B-D76E-49DA-8BD6-BF472224AEC0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI.Demo", "source\RevitLookup.UI.Demo\RevitLookup.UI.Demo.csproj", "{67B8906F-21B0-4CE3-82F7-8E608B9D53CA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "source\Benchmarks\Benchmarks.csproj", "{827646DF-D373-4D40-8F0B-1E9842E3CE9A}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug R21|Any CPU = Debug R21|Any CPU - Debug R22|Any CPU = Debug R22|Any CPU - Debug R23|Any CPU = Debug R23|Any CPU - Debug R24|Any CPU = Debug R24|Any CPU - Debug R25|Any CPU = Debug R25|Any CPU - Release R21|Any CPU = Release R21|Any CPU - Release R22|Any CPU = Release R22|Any CPU - Release R23|Any CPU = Release R23|Any CPU - Release R24|Any CPU = Release R24|Any CPU - Release R25|Any CPU = Release R25|Any CPU - Installer|Any CPU = Installer|Any CPU - UI.Demo Debug|Any CPU = UI.Demo Debug|Any CPU - UI.Demo Release|Any CPU = UI.Demo Release|Any CPU - Benchmark|Any CPU = Benchmark|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.UI.Demo Release|Any CPU.ActiveCfg = Release R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.UI.Demo Release|Any CPU.Build.0 = Release R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Benchmark|Any CPU.ActiveCfg = Release R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Installer|Any CPU.ActiveCfg = Release R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R21|Any CPU.ActiveCfg = Debug R21|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R21|Any CPU.Build.0 = Debug R21|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R22|Any CPU.ActiveCfg = Debug R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R22|Any CPU.Build.0 = Debug R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R23|Any CPU.ActiveCfg = Debug R23|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R23|Any CPU.Build.0 = Debug R23|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R24|Any CPU.ActiveCfg = Debug R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R24|Any CPU.Build.0 = Debug R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R25|Any CPU.ActiveCfg = Debug R25|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Debug R25|Any CPU.Build.0 = Debug R25|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R21|Any CPU.ActiveCfg = Release R21|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R21|Any CPU.Build.0 = Release R21|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R22|Any CPU.ActiveCfg = Release R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R22|Any CPU.Build.0 = Release R22|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R23|Any CPU.ActiveCfg = Release R23|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R23|Any CPU.Build.0 = Release R23|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R24|Any CPU.ActiveCfg = Release R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R24|Any CPU.Build.0 = Release R24|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R25|Any CPU.ActiveCfg = Release R25|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.Release R25|Any CPU.Build.0 = Release R25|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.UI.Demo Debug|Any CPU.ActiveCfg = Debug R25|Any CPU - {05C77115-2277-4DFC-8F95-BE37E5F1130F}.UI.Demo Debug|Any CPU.Build.0 = Debug R25|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.UI.Demo Debug|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.UI.Demo Release|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Installer|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Release R21|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Release R22|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Release R23|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Release R24|Any CPU.ActiveCfg = Release|Any CPU - {64D9C223-D070-46CD-A635-04FD4E1BEC3C}.Release R25|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.UI.Demo Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.UI.Demo Release|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Installer|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Installer|Any CPU.Build.0 = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Release R21|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Release R22|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Release R23|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Release R24|Any CPU.ActiveCfg = Release|Any CPU - {B3814652-9158-4056-A721-1A380DE74BAE}.Release R25|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.UI.Demo Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.UI.Demo Debug|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.UI.Demo Release|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.UI.Demo Release|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R21|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R22|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R23|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R24|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Debug R25|Any CPU.Build.0 = Debug|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R21|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R21|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R22|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R22|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R23|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R23|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R24|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R24|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R25|Any CPU.ActiveCfg = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Release R25|Any CPU.Build.0 = Release|Any CPU - {CE5C104B-D76E-49DA-8BD6-BF472224AEC0}.Installer|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.UI.Demo Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.UI.Demo Debug|Any CPU.Build.0 = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.UI.Demo Release|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.UI.Demo Release|Any CPU.Build.0 = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Installer|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Release R21|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Release R22|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Release R23|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Release R24|Any CPU.ActiveCfg = Release|Any CPU - {67B8906F-21B0-4CE3-82F7-8E608B9D53CA}.Release R25|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.UI.Demo Debug|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.UI.Demo Release|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Benchmark|Any CPU.Build.0 = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Installer|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Release R21|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Release R22|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Release R23|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Release R24|Any CPU.ActiveCfg = Release|Any CPU - {827646DF-D373-4D40-8F0B-1E9842E3CE9A}.Release R25|Any CPU.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DA402884-3505-43C8-8114-271D66001F6B} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.Abstractions", "source\RevitLookup.Abstractions\RevitLookup.Abstractions.csproj", "{71AAD043-A063-F08F-42F4-BF2AA43BEDA4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.Common", "source\RevitLookup.Common\RevitLookup.Common.csproj", "{73ABAE95-3197-9EDD-91B6-7E98656CF7D1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Automation", "Automation", "{BE4A8008-4A00-8C08-26C2-BD576741EBBE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "build\Build.csproj", "{7DF908B3-503D-51C2-3675-626DC2895B77}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Installer", "install\Installer.csproj", "{0B3682BA-1074-598D-D8A6-04BB7116F36C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{D585295F-7994-3649-1065-7AA403C41681}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LookupEngine.Abstractions", "source\LookupEngine.Abstractions\LookupEngine.Abstractions.csproj", "{C075FD80-58C0-8D06-69F2-853E4D51AFE8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LookupEngine", "source\LookupEngine\LookupEngine.csproj", "{BD145DF8-35DF-8587-A26B-968A550D1D06}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frontend", "Frontend", "{CE609670-85B9-0D16-FB54-ED063D5D8A6D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI.Abstractions", "source\RevitLookup.UI.Abstractions\RevitLookup.UI.Abstractions.csproj", "{B687BEC0-11DB-7690-478A-444D8D9FCE25}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI.Framework", "source\RevitLookup.UI.Framework\RevitLookup.UI.Framework.csproj", "{925534FD-C38B-5571-23B0-62982B24DC6C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI.Playground", "source\RevitLookup.UI.Playground\RevitLookup.UI.Playground.csproj", "{4FADCDA4-2A63-BF3E-03C8-20102440CA7C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup.UI", "source\RevitLookup.UI\RevitLookup.UI.csproj", "{DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Revit", "Revit", "{D64246B1-3E22-9D95-23C6-14262B074D58}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookupObsolete", "source\RevitLookupObsolete\RevitLookupObsolete.csproj", "{897CB786-AC5A-18EE-3091-7E14935796D5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitLookup", "source\RevitLookup\RevitLookup.csproj", "{7B7CA95C-9873-5ADB-DBCF-B46046742163}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{089100B1-113F-4E66-888A-E83F3999EAFD}" + ProjectSection(SolutionItems) = preProject + Readme.md = Readme.md + Changelog.md = Changelog.md + Contributing.md = Contributing.md + Build\Build.Configuration.cs = Build\Build.Configuration.cs + Directory.Packages.props = Directory.Packages.props + Directory.Build.props = Directory.Build.props + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0AB3BF05-4346-4AA6-1389-037BE0695223}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LookupEngine.Tests.Performance", "tests\LookupEngine.Tests.Performance\LookupEngine.Tests.Performance.csproj", "{280FCE1F-F215-F89A-D710-1D9770067692}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LookupEngine.Tests.Unit", "tests\LookupEngine.Tests.Unit\LookupEngine.Tests.Unit.csproj", "{E8D6B99E-2C38-C524-525B-EF812BB3926C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug Engine|Any CPU = Debug Engine|Any CPU + Debug Frontend|Any CPU = Debug Frontend|Any CPU + Debug R21|Any CPU = Debug R21|Any CPU + Debug R22|Any CPU = Debug R22|Any CPU + Debug R23|Any CPU = Debug R23|Any CPU + Debug R24|Any CPU = Debug R24|Any CPU + Debug R25|Any CPU = Debug R25|Any CPU + Release Build|Any CPU = Release Build|Any CPU + Release Engine|Any CPU = Release Engine|Any CPU + Release Frontend|Any CPU = Release Frontend|Any CPU + Release R21|Any CPU = Release R21|Any CPU + Release R22|Any CPU = Release R22|Any CPU + Release R23|Any CPU = Release R23|Any CPU + Release R24|Any CPU = Release R24|Any CPU + Release R25|Any CPU = Release R25|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R21|Any CPU.Build.0 = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R22|Any CPU.Build.0 = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R23|Any CPU.Build.0 = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R24|Any CPU.Build.0 = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {71AAD043-A063-F08F-42F4-BF2AA43BEDA4}.Release R25|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R21|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R22|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R23|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R24|Any CPU.Build.0 = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {73ABAE95-3197-9EDD-91B6-7E98656CF7D1}.Release R25|Any CPU.Build.0 = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {7DF908B3-503D-51C2-3675-626DC2895B77}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release Build|Any CPU.Build.0 = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {0B3682BA-1074-598D-D8A6-04BB7116F36C}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug Engine|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release Engine|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R21|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R22|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R23|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R24|Any CPU.Build.0 = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {C075FD80-58C0-8D06-69F2-853E4D51AFE8}.Release R25|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug Engine|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release Engine|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R21|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R22|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R23|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R24|Any CPU.Build.0 = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {BD145DF8-35DF-8587-A26B-968A550D1D06}.Release R25|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R21|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R22|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R23|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R24|Any CPU.Build.0 = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {B687BEC0-11DB-7690-478A-444D8D9FCE25}.Release R25|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R21|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R22|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R23|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R24|Any CPU.Build.0 = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {925534FD-C38B-5571-23B0-62982B24DC6C}.Release R25|Any CPU.Build.0 = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug Frontend|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R21|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R22|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R23|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R24|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Debug R25|Any CPU.Build.0 = Debug|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release Frontend|Any CPU.Build.0 = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R21|Any CPU.Build.0 = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R22|Any CPU.Build.0 = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R23|Any CPU.Build.0 = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R24|Any CPU.Build.0 = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1}.Release R25|Any CPU.Build.0 = Release|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug Engine|Any CPU.ActiveCfg = Debug R25|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug Frontend|Any CPU.ActiveCfg = Debug R25|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug R21|Any CPU.ActiveCfg = Debug R21|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug R22|Any CPU.ActiveCfg = Debug R22|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug R23|Any CPU.ActiveCfg = Debug R23|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug R24|Any CPU.ActiveCfg = Debug R24|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Debug R25|Any CPU.ActiveCfg = Debug R25|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release Build|Any CPU.ActiveCfg = Release R25|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release Engine|Any CPU.ActiveCfg = Release R24|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release Frontend|Any CPU.ActiveCfg = Release R25|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release R21|Any CPU.ActiveCfg = Release R21|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release R22|Any CPU.ActiveCfg = Release R22|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release R23|Any CPU.ActiveCfg = Release R23|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release R24|Any CPU.ActiveCfg = Release R24|Any CPU + {897CB786-AC5A-18EE-3091-7E14935796D5}.Release R25|Any CPU.ActiveCfg = Release R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug Engine|Any CPU.ActiveCfg = Debug R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug Frontend|Any CPU.ActiveCfg = Debug R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R21|Any CPU.ActiveCfg = Debug R21|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R21|Any CPU.Build.0 = Debug R21|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R22|Any CPU.ActiveCfg = Debug R22|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R22|Any CPU.Build.0 = Debug R22|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R23|Any CPU.ActiveCfg = Debug R23|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R23|Any CPU.Build.0 = Debug R23|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R24|Any CPU.ActiveCfg = Debug R24|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R24|Any CPU.Build.0 = Debug R24|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R25|Any CPU.ActiveCfg = Debug R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Debug R25|Any CPU.Build.0 = Debug R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release Build|Any CPU.ActiveCfg = Release R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release Engine|Any CPU.ActiveCfg = Release R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release Frontend|Any CPU.ActiveCfg = Release R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R21|Any CPU.ActiveCfg = Release R21|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R21|Any CPU.Build.0 = Release R21|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R22|Any CPU.ActiveCfg = Release R22|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R22|Any CPU.Build.0 = Release R22|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R23|Any CPU.ActiveCfg = Release R23|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R23|Any CPU.Build.0 = Release R23|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R24|Any CPU.ActiveCfg = Release R24|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R24|Any CPU.Build.0 = Release R24|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R25|Any CPU.ActiveCfg = Release R25|Any CPU + {7B7CA95C-9873-5ADB-DBCF-B46046742163}.Release R25|Any CPU.Build.0 = Release R25|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release Engine|Any CPU.Build.0 = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {280FCE1F-F215-F89A-D710-1D9770067692}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug Engine|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug Engine|Any CPU.Build.0 = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug Frontend|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug R21|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug R22|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug R23|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug R24|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Debug R25|Any CPU.ActiveCfg = Debug|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release Build|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release Engine|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release Engine|Any CPU.Build.0 = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release Frontend|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release R21|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release R22|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release R23|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release R24|Any CPU.ActiveCfg = Release|Any CPU + {E8D6B99E-2C38-C524-525B-EF812BB3926C}.Release R25|Any CPU.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {7DF908B3-503D-51C2-3675-626DC2895B77} = {BE4A8008-4A00-8C08-26C2-BD576741EBBE} + {0B3682BA-1074-598D-D8A6-04BB7116F36C} = {BE4A8008-4A00-8C08-26C2-BD576741EBBE} + {C075FD80-58C0-8D06-69F2-853E4D51AFE8} = {D585295F-7994-3649-1065-7AA403C41681} + {BD145DF8-35DF-8587-A26B-968A550D1D06} = {D585295F-7994-3649-1065-7AA403C41681} + {B687BEC0-11DB-7690-478A-444D8D9FCE25} = {CE609670-85B9-0D16-FB54-ED063D5D8A6D} + {925534FD-C38B-5571-23B0-62982B24DC6C} = {CE609670-85B9-0D16-FB54-ED063D5D8A6D} + {4FADCDA4-2A63-BF3E-03C8-20102440CA7C} = {CE609670-85B9-0D16-FB54-ED063D5D8A6D} + {DED9FF57-E78C-F4C2-9CFD-368819DFE4C1} = {CE609670-85B9-0D16-FB54-ED063D5D8A6D} + {897CB786-AC5A-18EE-3091-7E14935796D5} = {D64246B1-3E22-9D95-23C6-14262B074D58} + {7B7CA95C-9873-5ADB-DBCF-B46046742163} = {D64246B1-3E22-9D95-23C6-14262B074D58} + {280FCE1F-F215-F89A-D710-1D9770067692} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + {E8D6B99E-2C38-C524-525B-EF812BB3926C} = {0AB3BF05-4346-4AA6-1389-037BE0695223} + EndGlobalSection +EndGlobal diff --git a/RevitLookup.slnx b/RevitLookup.slnx new file mode 100644 index 000000000..d084eeff0 --- /dev/null +++ b/RevitLookup.slnx @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/RevitLookup.slnx.DotSettings b/RevitLookup.slnx.DotSettings new file mode 100644 index 000000000..f45b7570c --- /dev/null +++ b/RevitLookup.slnx.DotSettings @@ -0,0 +1,5 @@ + + True + True + True + True \ No newline at end of file diff --git a/build/Build.Clean.cs b/build/Build.Clean.cs index 9e78c80cf..70a12831b 100644 --- a/build/Build.Clean.cs +++ b/build/Build.Clean.cs @@ -8,12 +8,12 @@ sealed partial class Build .Executes(() => { CleanDirectory(ArtifactsDirectory); - foreach (var project in Solution.AllProjects.Where(project => project != Solution.Build)) + foreach (var project in Solution.AllProjects.Where(project => project != Solution.Automation.Build)) { CleanDirectory(project.Directory / "bin"); CleanDirectory(project.Directory / "obj"); } - + foreach (var configuration in GlobBuildConfigurations()) DotNetClean(settings => settings .SetConfiguration(configuration) diff --git a/build/Build.Configuration.cs b/build/Build.Configuration.cs index 7b505efac..c69924974 100644 --- a/build/Build.Configuration.cs +++ b/build/Build.Configuration.cs @@ -13,7 +13,7 @@ protected override void OnBuildInitialized() InstallersMap = new() { - { Solution.Installer, Solution.RevitLookup } + { Solution.Automation.Installer, Solution.Revit.RevitLookup } }; VersionMap = new() diff --git a/build/Build.cs b/build/Build.cs index d0aab9f00..def828e25 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,4 +1,3 @@ -using Nuke.Common; using Nuke.Common.Git; using Nuke.Common.ProjectModel; diff --git a/build/Build.csproj b/build/Build.csproj index 55d9359a0..bd31d8f84 100644 --- a/build/Build.csproj +++ b/build/Build.csproj @@ -2,19 +2,16 @@ Exe + disable CS0649;CS0169 - latest - true - net8.0 + net9.0 .. .. 1 - Release;Debug - AnyCPU - + diff --git a/global.json b/global.json index 75a80e90b..894573b73 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,7 @@ { "sdk": { - "version": "8.0.0", - "rollForward": "latestMinor" + "version": "9.0.0", + "rollForward": "latestMinor", + "allowPrerelease": true } } \ No newline at end of file diff --git a/doc/Images/ja_1.png b/history/Images/ja_1.png similarity index 100% rename from doc/Images/ja_1.png rename to history/Images/ja_1.png diff --git a/doc/Images/ja_2.png b/history/Images/ja_2.png similarity index 100% rename from doc/Images/ja_2.png rename to history/Images/ja_2.png diff --git a/doc/Images/ja_3.png b/history/Images/ja_3.png similarity index 100% rename from doc/Images/ja_3.png rename to history/Images/ja_3.png diff --git a/doc/Images/ja_4.png b/history/Images/ja_4.png similarity index 100% rename from doc/Images/ja_4.png rename to history/Images/ja_4.png diff --git a/doc/Images/ja_5.png b/history/Images/ja_5.png similarity index 100% rename from doc/Images/ja_5.png rename to history/Images/ja_5.png diff --git a/doc/Images/ja_6.png b/history/Images/ja_6.png similarity index 100% rename from doc/Images/ja_6.png rename to history/Images/ja_6.png diff --git a/doc/Readme_2005-05-11.doc b/history/Readme_2005-05-11.doc similarity index 100% rename from doc/Readme_2005-05-11.doc rename to history/Readme_2005-05-11.doc diff --git a/doc/Readme_2005-05-11.md b/history/Readme_2005-05-11.md similarity index 98% rename from doc/Readme_2005-05-11.md rename to history/Readme_2005-05-11.md index 88db5a3e2..d205213ba 100644 --- a/doc/Readme_2005-05-11.md +++ b/history/Readme_2005-05-11.md @@ -1,120 +1,120 @@ -# Revit Lookup (Formerly known as RvtMgdDbg) - -Jim Awe -
Autodesk, Inc. -
05/11/2005 - -
- - -Warning, this document is currently obsolete. - -08808006 [Revit SDK documentation outdated...] - -Contains outdated or non-functional information regarding creating the 'RevitLookup.addin' file and the associated file which belong in the addins folder. (If you cut and paste the suggested text as from RevitLookup.doc to create RevitLookup.addin it will fail when Revit starts) - -In 2012 SDK, there is a compiled DLL file, and a working Addin file. - -In the 2013 SDK, there is no compiled DLL file (or instructions on compiling DLL), and there is no Addin file. - -In the 2014 SDK there is no compiled DLL file (or instructions on compiling DLL), but there is an Addin file. - -In all three cases, the date listed for the Documentation (Word Doc) is 05/11/2005, and much of the information is out of date. - - -
- -Revit Lookup is a program designed with several goals: - -- To provide a comprehensive test of the Managed API of Revit -- To provide sample code and utility classes for 3rd Party developers -- To provide “scaffolding” for quick tests of issues when they arise -- To aid my own learning experience on the Revit API - -Currently, the following commands exist (all accessed from the “External Tools” menu): - - - -## Hello World... - -The classic bare-bones test. Just brings up an Alert box to show that the connection to the external module is working. - -## Snoop DB... - - - -This command allows you to browse all of the Elements within the current document and view their exposed properties. There has to be code written to extract all the individual properties of an object. As a result, when new classes or methods are added to the system, they will not be visible until code is explicitly written to display them. Because, the properties of an object are obtained in a top-down manner, all object types will at least be able to display common base class properties, even when newly added. - -When an item in the data list appears in bold typeface, it means that there is “Drill down” information. Click on that row and a nested Form (Dialog Box) will bring up more detailed information about that data item. For instance, clicking on any item that lists a ParameterSet will bring up a nested Form displaying the contents of the set. - -NOTE: when “Drilling down”, the Forms will stack on top of each other. You could keep drilling down a long way if you aren’t paying attention. It is up to you to make sure you don’t get lost in all of the stacked up Forms. - -The DrillDown information on a Class Separator (the light blue lines), will allow you to view information about the given class. - - - -Also, in the left-hand pane, you can right-click on a particular object and get additional information. - - - -Choosing “Browse Using Reflection...” will bring up a Generic PropertyGrid Form that uses .NET Reflection to browse all the properties. Here, there is no code written specifically in Revit Lookup to retrieve, format, and display the properties. - - - -NOTE: Because we have no control over how items are displayed, read-only values appear in Grey, and editable values appear in Bold. This form is not setup to correctly handle edits, so making changes is completely at your own risk. - -You can continue to browse generically using Reflection if you right-click on one of the items in the PropertyGrid. You get options to see either the Class info or the Object info. - -## Snoop Current Selection... - -Same as the above command, except that it starts you off Snooping only the elements that were part of the current selection set. - -## Snoop Application... - -Same as above, except that you start out at the Autodesk.Revit.Application object which is originally passed to the command. - -## Test Framework ... - -This command packages a set of individual tests into a single location. As new tests are written, they are plugged into this same Form without the need to define new external commands and hook them up to the system. The black “CLS” nodes of the tree represent which Class the tests concern. The grey check mark nodes represent an individual test. To run a test, simply choose a check mark node and press OK. - -As of now, there are only a few tests, but more will be added over time. - - - -## Set Up - -The Revit API now offers the ability to register API applications via an .addin manifest file. - -Manifest files will be read automatically by Revit when they are places in one of two locations on a user's system: - -- In a non-user specific location in "application data" - - For Windows XP – C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2012 - - For Vista/Windows 7 – C:\ProgramData\Autodesk\Revit\Addins\2012 -- In a user specific location in "application data" - - For Windows XP – C:\Documents and Settings\\Application Data\Autodesk\Revit\Addins\2012 - - For Vista/Windows 7 – C:\Users\\AppData\Roaming\Autodesk\Revit\Addins\2012 - -All files named `.addin` in these locations will be read and processed by Revit during startup. - -The content of RevitLookup.addin: - -``` - - - - RevitLookup - RevitLookup.dll - 6066CBF6-9034-41dd-A2A6-B3761C1362FF - RevitLookup.App - - -``` - -## Known Issues - -As of this date, there are a few known issues: - -- Random exceptions when browsing Forms. There is a strange work-around in some of the Form constructors that seems to get around a lot of the exceptions, but there is still the occasional problem. Usually, they give the exception message “Overflow or underflow operation”. The exceptions are caught and you will be returned to the editor window and can continue. -- The Snoop XML Form seems to be especially flaky. This was ported directly over from the AutoCAD version of MgdDbg, so I’m not sure what the deal is yet because it seems much more stable over there. -- Trying to get the Analytical model of walls if they aren’t a load-bearing wall causes an Assert. Simply click on “Ignore All” and it won’t bother you anymore. -- Trying to get the Room or analytical model of a FamilyInstance asserts that the TopologyId is incorrect. Simply click on “Ignore All” and it won’t bother you anymore. +# Revit Lookup (Formerly known as RvtMgdDbg) + +Jim Awe +
Autodesk, Inc. +
05/11/2005 + +
+ + +Warning, this document is currently obsolete. + +08808006 [Revit SDK documentation outdated...] + +Contains outdated or non-functional information regarding creating the 'RevitLookup.addin' file and the associated file which belong in the addins folder. (If you cut and paste the suggested text as from RevitLookup.doc to create RevitLookup.addin it will fail when Revit starts) + +In 2012 SDK, there is a compiled DLL file, and a working Addin file. + +In the 2013 SDK, there is no compiled DLL file (or instructions on compiling DLL), and there is no Addin file. + +In the 2014 SDK there is no compiled DLL file (or instructions on compiling DLL), but there is an Addin file. + +In all three cases, the date listed for the Documentation (Word Doc) is 05/11/2005, and much of the information is out of date. + + +
+ +Revit Lookup is a program designed with several goals: + +- To provide a comprehensive test of the Managed API of Revit +- To provide sample code and utility classes for 3rd Party developers +- To provide “scaffolding” for quick tests of issues when they arise +- To aid my own learning experience on the Revit API + +Currently, the following commands exist (all accessed from the “External Tools” menu): + + + +## Hello World... + +The classic bare-bones test. Just brings up an Alert box to show that the connection to the external module is working. + +## Snoop DB... + + + +This command allows you to browse all of the Elements within the current document and view their exposed properties. There has to be code written to extract all the individual properties of an object. As a result, when new classes or methods are added to the system, they will not be visible until code is explicitly written to display them. Because, the properties of an object are obtained in a top-down manner, all object types will at least be able to display common base class properties, even when newly added. + +When an item in the data list appears in bold typeface, it means that there is “Drill down” information. Click on that row and a nested Form (Dialog Box) will bring up more detailed information about that data item. For instance, clicking on any item that lists a ParameterSet will bring up a nested Form displaying the contents of the set. + +NOTE: when “Drilling down”, the Forms will stack on top of each other. You could keep drilling down a long way if you aren’t paying attention. It is up to you to make sure you don’t get lost in all of the stacked up Forms. + +The DrillDown information on a Class Separator (the light blue lines), will allow you to view information about the given class. + + + +Also, in the left-hand pane, you can right-click on a particular object and get additional information. + + + +Choosing “Browse Using Reflection...” will bring up a Generic PropertyGrid Form that uses .NET Reflection to browse all the properties. Here, there is no code written specifically in Revit Lookup to retrieve, format, and display the properties. + + + +NOTE: Because we have no control over how items are displayed, read-only values appear in Grey, and editable values appear in Bold. This form is not setup to correctly handle edits, so making changes is completely at your own risk. + +You can continue to browse generically using Reflection if you right-click on one of the items in the PropertyGrid. You get options to see either the Class info or the Object info. + +## Snoop Current Selection... + +Same as the above command, except that it starts you off Snooping only the elements that were part of the current selection set. + +## Snoop Application... + +Same as above, except that you start out at the Autodesk.Revit.Application object which is originally passed to the command. + +## Test Framework ... + +This command packages a set of individual tests into a single location. As new tests are written, they are plugged into this same Form without the need to define new external commands and hook them up to the system. The black “CLS” nodes of the tree represent which Class the tests concern. The grey check mark nodes represent an individual test. To run a test, simply choose a check mark node and press OK. + +As of now, there are only a few tests, but more will be added over time. + + + +## Set Up + +The Revit API now offers the ability to register API applications via an .addin manifest file. + +Manifest files will be read automatically by Revit when they are places in one of two locations on a user's system: + +- In a non-user specific location in "application data" + - For Windows XP – C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2012 + - For Vista/Windows 7 – C:\ProgramData\Autodesk\Revit\Addins\2012 +- In a user specific location in "application data" + - For Windows XP – C:\Documents and Settings\\Application Data\Autodesk\Revit\Addins\2012 + - For Vista/Windows 7 – C:\Users\\AppData\Roaming\Autodesk\Revit\Addins\2012 + +All files named `.addin` in these locations will be read and processed by Revit during startup. + +The content of RevitLookup.addin: + +``` + + + + RevitLookup + RevitLookup.dll + 6066CBF6-9034-41dd-A2A6-B3761C1362FF + RevitLookup.App + + +``` + +## Known Issues + +As of this date, there are a few known issues: + +- Random exceptions when browsing Forms. There is a strange work-around in some of the Form constructors that seems to get around a lot of the exceptions, but there is still the occasional problem. Usually, they give the exception message “Overflow or underflow operation”. The exceptions are caught and you will be returned to the editor window and can continue. +- The Snoop XML Form seems to be especially flaky. This was ported directly over from the AutoCAD version of MgdDbg, so I’m not sure what the deal is yet because it seems much more stable over there. +- Trying to get the Analytical model of walls if they aren’t a load-bearing wall causes an Assert. Simply click on “Ignore All” and it won’t bother you anymore. +- Trying to get the Room or analytical model of a FamilyInstance asserts that the TopologyId is incorrect. Simply click on “Ignore All” and it won’t bother you anymore. diff --git a/doc/Wishlist.md b/history/Wishlist.md similarity index 100% rename from doc/Wishlist.md rename to history/Wishlist.md diff --git a/install/Installer.csproj b/install/Installer.csproj index 6a6de95ff..f8995b453 100644 --- a/install/Installer.csproj +++ b/install/Installer.csproj @@ -1,13 +1,14 @@  + Exe - latest - x64 net48 false + - - + + + diff --git a/source/RevitLookup/.editorconfig b/source/.editorconfig similarity index 100% rename from source/RevitLookup/.editorconfig rename to source/.editorconfig diff --git a/source/Benchmarks/Benchmark.cs b/source/Benchmarks/Benchmark.cs deleted file mode 100644 index f50e18ff9..000000000 --- a/source/Benchmarks/Benchmark.cs +++ /dev/null @@ -1,4 +0,0 @@ -using BenchmarkDotNet.Running; -using Benchmarks; - -BenchmarkRunner.Run(); \ No newline at end of file diff --git a/source/Benchmarks/Benchmarks.csproj b/source/Benchmarks/Benchmarks.csproj deleted file mode 100644 index 5321527a1..000000000 --- a/source/Benchmarks/Benchmarks.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - Exe - latest - enable - net48 - - - - - diff --git a/source/Benchmarks/ClosureBenchmark.cs b/source/Benchmarks/ClosureBenchmark.cs deleted file mode 100644 index bb1e03b1b..000000000 --- a/source/Benchmarks/ClosureBenchmark.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using BenchmarkDotNet.Attributes; - -namespace Benchmarks; - -[ShortRunJob] -[MemoryDiagnoser] -public class ClosureBenchmark -{ - [GlobalSetup] - public void Setup() - { - Manager = new ExtensionManager("context"); - } - - [Params("Text", 12d)] public object Parameter { get; set; } - public ExtensionManager Manager { get; set; } - - [Benchmark] - public void ClosureMethod() - { - Manager.Register("Extension", () => Parameter.ToString()); - } - - [Benchmark] - public void NonClosureMethod() - { - Manager.Register("Extension", Parameter, extension => - { - extension.Result = extension.Value.ToString(); - }); - } -} - -public sealed class ExtensionManager -{ - private readonly string _context; - - public ExtensionManager(string context) - { - _context = context; - } - - public List Descriptors { get; set; } = new(); - - public void Register(string name, T value, Action> extension) - { - var descriptorExtension = new DescriptorExtension - { - Value = value, - Context = _context - }; - - var descriptor = new ObjectDescriptor - { - Label = name - }; - - try - { - extension.Invoke(descriptorExtension); - descriptor.Value = new SnoopableObject(_context, descriptorExtension.Result); - } - catch (Exception exception) - { - descriptor.Value = new SnoopableObject(_context, exception); - } - - Descriptors.Add(descriptor); - } - - public void Register(string name, Func result) - { - var descriptor = new ObjectDescriptor - { - Label = name - }; - - try - { - descriptor.Value = new SnoopableObject(_context, result()); - } - catch (Exception exception) - { - descriptor.Value = new SnoopableObject(_context, exception); - } - - Descriptors.Add(descriptor); - } -} - -public sealed class DescriptorExtension -{ - public string Context { get; set; } - public T Value { get; set; } - public object Result { get; set; } -} - -public sealed class ObjectDescriptor : Descriptor -{ - public ObjectDescriptor() - { - } - - public ObjectDescriptor(object value) - { - Label = value.ToString(); - } -} - -public abstract class Descriptor : IComparable, IComparable -{ - public string Type { get; set; } - public string Label { get; set; } - public SnoopableObject Value { get; set; } - - public int CompareTo(object obj) - { - if (ReferenceEquals(null, obj)) return 1; - if (ReferenceEquals(this, obj)) return 0; - return obj is Descriptor other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(Descriptor)}"); - } - - public int CompareTo(Descriptor other) - { - if (ReferenceEquals(this, other)) return 0; - if (ReferenceEquals(null, other)) return 1; - var typeComparison = string.Compare(Type, other.Type, StringComparison.Ordinal); - if (typeComparison != 0) return typeComparison; - return string.Compare(Label, other.Label, StringComparison.Ordinal); - } -} - -public sealed class SnoopableObject -{ - public SnoopableObject(string context, object obj) - { - Object = obj; - Context = context; - } - - public object Object { get; } - public string Context { get; } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IDescriptorCollector.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorCollector.cs similarity index 95% rename from source/RevitLookup/Core/Contracts/IDescriptorCollector.cs rename to source/LookupEngine.Abstractions/Configuration/IDescriptorCollector.cs index c47ad5858..7183d0ff0 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorCollector.cs +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorCollector.cs @@ -18,7 +18,7 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Contracts; +namespace LookupEngine.Abstractions.Configuration; /// /// Indicates that the descriptor can retrieve object members by reflection diff --git a/source/RevitLookup/Core/Contracts/IDescriptorEnumerator.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorEnumerator.cs similarity index 96% rename from source/RevitLookup/Core/Contracts/IDescriptorEnumerator.cs rename to source/LookupEngine.Abstractions/Configuration/IDescriptorEnumerator.cs index 54d76f4ae..0349f203c 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorEnumerator.cs +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorEnumerator.cs @@ -20,7 +20,7 @@ using System.Collections; -namespace RevitLookup.Core.Contracts; +namespace LookupEngine.Abstractions.Configuration; /// /// Indicates that the descriptor is handled as a collection of descriptors diff --git a/source/RevitLookup/Core/Contracts/IDescriptorExtension.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorExtension.cs similarity index 95% rename from source/RevitLookup/Core/Contracts/IDescriptorExtension.cs rename to source/LookupEngine.Abstractions/Configuration/IDescriptorExtension.cs index dc44aa5d6..76aff48bd 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorExtension.cs +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorExtension.cs @@ -18,7 +18,7 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Contracts; +namespace LookupEngine.Abstractions.Configuration; /// /// Indicates that the descriptor can interact with the UI and execute commands diff --git a/source/LookupEngine.Abstractions/Configuration/IDescriptorExtension{T}.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorExtension{T}.cs new file mode 100644 index 000000000..543c8aa88 --- /dev/null +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorExtension{T}.cs @@ -0,0 +1,29 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +namespace LookupEngine.Abstractions.Configuration; + +/// +/// Indicates that the descriptor can interact with the UI and execute commands +/// +public interface IDescriptorExtension : IDescriptorCollector +{ + void RegisterExtensions(IExtensionManager manager); +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IDescriptorRedirection.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector.cs similarity index 87% rename from source/RevitLookup/Core/Contracts/IDescriptorRedirection.cs rename to source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector.cs index d603c242e..fce809dae 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorRedirection.cs +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector.cs @@ -18,12 +18,12 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Contracts; +namespace LookupEngine.Abstractions.Configuration; /// /// Indicates that the object can be redirected to another /// -public interface IDescriptorRedirection +public interface IDescriptorRedirector { - bool TryRedirect(Document context, string target, out object output); + bool TryRedirect(string target, out object result); } \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector{T}.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector{T}.cs new file mode 100644 index 000000000..78d13e895 --- /dev/null +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorRedirector{T}.cs @@ -0,0 +1,29 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +namespace LookupEngine.Abstractions.Configuration; + +/// +/// Indicates that the object can be redirected to another +/// +public interface IDescriptorRedirector +{ + bool TryRedirect(string target, TContext context, out object result); +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IDescriptorResolver.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorResolver.cs similarity index 87% rename from source/RevitLookup/Core/Contracts/IDescriptorResolver.cs rename to source/LookupEngine.Abstractions/Configuration/IDescriptorResolver.cs index 93a0dc89a..71fa2dce8 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorResolver.cs +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorResolver.cs @@ -19,13 +19,14 @@ // (Rights in Technical Data and Computer Software), as applicable. using System.Reflection; +using LookupEngine.Abstractions.Decomposition; -namespace RevitLookup.Core.Contracts; +namespace LookupEngine.Abstractions.Configuration; /// /// Indicates that the descriptor can decide to call methods/properties with parameters or override their values /// public interface IDescriptorResolver : IDescriptorCollector { - Func Resolve(Document context, string target, ParameterInfo[] parameters); + Func? Resolve(string target, ParameterInfo[] parameters); } \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Configuration/IDescriptorResolver{T}.cs b/source/LookupEngine.Abstractions/Configuration/IDescriptorResolver{T}.cs new file mode 100644 index 000000000..cc59bcedf --- /dev/null +++ b/source/LookupEngine.Abstractions/Configuration/IDescriptorResolver{T}.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Abstractions.Configuration; + +/// +/// Indicates that the descriptor can decide to call methods/properties with parameters or override their values +/// +public interface IDescriptorResolver : IDescriptorCollector +{ + Func? Resolve(string target, ParameterInfo[] parameters); +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IExtensionManager.cs b/source/LookupEngine.Abstractions/Configuration/IExtensionManager.cs similarity index 86% rename from source/RevitLookup/Core/Contracts/IExtensionManager.cs rename to source/LookupEngine.Abstractions/Configuration/IExtensionManager.cs index f5ef913e7..d919fa036 100644 --- a/source/RevitLookup/Core/Contracts/IExtensionManager.cs +++ b/source/LookupEngine.Abstractions/Configuration/IExtensionManager.cs @@ -18,10 +18,11 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Contracts; +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Abstractions.Configuration; public interface IExtensionManager { - Document Context { get; } - void Register(string methodName, Func context); + void Register(string name, Func extension); } \ No newline at end of file diff --git a/source/RevitLookup.UI/Application.cs b/source/LookupEngine.Abstractions/Configuration/IExtensionManager{T}.cs similarity index 81% rename from source/RevitLookup.UI/Application.cs rename to source/LookupEngine.Abstractions/Configuration/IExtensionManager{T}.cs index be6ad1c56..22c910d09 100644 --- a/source/RevitLookup.UI/Application.cs +++ b/source/LookupEngine.Abstractions/Configuration/IExtensionManager{T}.cs @@ -18,12 +18,11 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using Wpf.Ui.Controls; +using LookupEngine.Abstractions.Decomposition; -namespace Wpf.Ui; +namespace LookupEngine.Abstractions.Configuration; -public static class Application +public interface IExtensionManager { - public static FluentWindow MainWindow { get; set; } - public static List Windows { get; set; } = new(8); + void Register(string name, Func extension); } \ No newline at end of file diff --git a/source/RevitLookup/Views/Pages/SettingsPage.xaml.cs b/source/LookupEngine.Abstractions/Decomposition/Containers/Variant.cs similarity index 72% rename from source/RevitLookup/Views/Pages/SettingsPage.xaml.cs rename to source/LookupEngine.Abstractions/Decomposition/Containers/Variant.cs index 2a21f995e..c237918f1 100644 --- a/source/RevitLookup/Views/Pages/SettingsPage.xaml.cs +++ b/source/LookupEngine.Abstractions/Decomposition/Containers/Variant.cs @@ -18,19 +18,21 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using RevitLookup.ViewModels.Pages; -using Wpf.Ui.Controls; +namespace LookupEngine.Abstractions.Decomposition.Containers; -namespace RevitLookup.Views.Pages; - -public sealed partial class SettingsPage : INavigableView +internal sealed class Variant : IVariant { - public SettingsPage(SettingsViewModel viewModel) + public Variant(object value) + { + Value = value; + } + + public Variant(object value, string description) { - ViewModel = viewModel; - InitializeComponent(); - DataContext = this; + Value = value; + Description = description; } - public SettingsViewModel ViewModel { get; } + public object Value { get; } + public string? Description { get; } } \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Decomposition/Containers/Variants{T}.cs b/source/LookupEngine.Abstractions/Decomposition/Containers/Variants{T}.cs new file mode 100644 index 000000000..fb925fcb8 --- /dev/null +++ b/source/LookupEngine.Abstractions/Decomposition/Containers/Variants{T}.cs @@ -0,0 +1,94 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; + +namespace LookupEngine.Abstractions.Decomposition.Containers; + +/// +/// Represents a collection of variants +/// +/// The type of the variants +/// The initial variants capacity. Required for atomic performance optimizations +internal sealed class Variants(int capacity) : IVariant, IVariantsCollection, IReadOnlyCollection +{ + private readonly List _items = new(capacity); + + /// + /// Gets the number of variants + /// + public int Count => _items.Count; + + public object Value => _items; + public string? Description => null; + + /// + /// Adds a new variant + /// + /// The variant collection with a new value + public IVariantsCollection Add(T? result) + { + if (result is null) return this; + if (result is ICollection {Count: 0}) return this; + + _items.Add(new Variant(result)); + + return this; + } + + /// + /// Adds a new variant with description + /// + /// The variant collection with a new value + public IVariantsCollection Add(T? result, string description) + { + if (result is null) return this; + if (result is ICollection {Count: 0}) return this; + + _items.Add(new Variant(result, description)); + + return this; + } + + public IVariant Consume() + { + return this; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _items.GetEnumerator(); + } + + public object GetResult() + { + return this; + } + + public string? GetMetadata() + { + return null; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IVariants.cs b/source/LookupEngine.Abstractions/Decomposition/Descriptor.cs similarity index 78% rename from source/RevitLookup/Core/Contracts/IVariants.cs rename to source/LookupEngine.Abstractions/Decomposition/Descriptor.cs index 554efdf0d..ad776f4e1 100644 --- a/source/RevitLookup/Core/Contracts/IVariants.cs +++ b/source/LookupEngine.Abstractions/Decomposition/Descriptor.cs @@ -18,15 +18,15 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Contracts; +using System.Diagnostics; +using JetBrains.Annotations; -public interface IVariants : IReadOnlyCollection -{ - Variant Single(); -} +namespace LookupEngine.Abstractions.Decomposition; -public interface IVariants : IVariants +[PublicAPI] +[DebuggerDisplay("Name = {Name}")] +public abstract class Descriptor { - Variants Add(T result); - Variants Add(T result, string description); + public string? Name { get; init; } + public string? Description { get; set; } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Objects/Variant.cs b/source/LookupEngine.Abstractions/Decomposition/IVariant.cs similarity index 86% rename from source/RevitLookup/Core/Objects/Variant.cs rename to source/LookupEngine.Abstractions/Decomposition/IVariant.cs index 8ffabc45d..11b49c8e8 100644 --- a/source/RevitLookup/Core/Objects/Variant.cs +++ b/source/LookupEngine.Abstractions/Decomposition/IVariant.cs @@ -18,10 +18,10 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Objects; +namespace LookupEngine.Abstractions.Decomposition; -public sealed class Variant +public interface IVariant { - public string Description { get; init; } - public object Object { get; init; } + object Value { get; } + string? Description { get; } } \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Decomposition/IVariantsCollection{T}.cs b/source/LookupEngine.Abstractions/Decomposition/IVariantsCollection{T}.cs new file mode 100644 index 000000000..fa346acbc --- /dev/null +++ b/source/LookupEngine.Abstractions/Decomposition/IVariantsCollection{T}.cs @@ -0,0 +1,8 @@ +namespace LookupEngine.Abstractions.Decomposition; + +public interface IVariantsCollection +{ + IVariantsCollection Add(T? result); + IVariantsCollection Add(T? result, string description); + IVariant Consume(); +} \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Decomposition/Variants.cs b/source/LookupEngine.Abstractions/Decomposition/Variants.cs new file mode 100644 index 000000000..7c0d7c86f --- /dev/null +++ b/source/LookupEngine.Abstractions/Decomposition/Variants.cs @@ -0,0 +1,46 @@ +using LookupEngine.Abstractions.Decomposition.Containers; + +namespace LookupEngine.Abstractions.Decomposition; + +/// +/// A factory for . +/// +public static class Variants +{ + /// + /// Creates a variant collection with a single value + /// + /// A variant collection containing the specified value + public static IVariant Value(object value) + { + return new Variant(value); + } + + public static IVariant Value(object value, string description) + { + return new Variant(value, description); + } + + public static IVariantsCollection Values(int capacity) + { + return new Variants(capacity); + } + + /// + /// Creates an empty variant collection + /// + /// An empty variant collection + /// An empty collection is returned when there are no solutions for a member + public static IVariant Empty() + { + return new Variants(0); + } + + /// + /// A variant that disables the member calculation + /// + public static IVariant Disabled() + { + return new Variant(new InvalidOperationException("Member execution disabled")); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Enums/MemberAttributes.cs b/source/LookupEngine.Abstractions/Enums/MemberAttributes.cs similarity index 96% rename from source/RevitLookup/Core/Enums/MemberAttributes.cs rename to source/LookupEngine.Abstractions/Enums/MemberAttributes.cs index 6e1330050..65f0662b9 100644 --- a/source/RevitLookup/Core/Enums/MemberAttributes.cs +++ b/source/LookupEngine.Abstractions/Enums/MemberAttributes.cs @@ -18,13 +18,14 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Enums; +namespace LookupEngine.Abstractions.Enums; [Flags] public enum MemberAttributes { Private = 0b1, Static = 0b10, + Field = 0b100, Property = 0b1000, Method = 0b10000, diff --git a/source/LookupEngine.Abstractions/LookupEngine.Abstractions.csproj b/source/LookupEngine.Abstractions/LookupEngine.Abstractions.csproj new file mode 100644 index 000000000..16a5e3f7f --- /dev/null +++ b/source/LookupEngine.Abstractions/LookupEngine.Abstractions.csproj @@ -0,0 +1,11 @@ + + + + net48;net8.0-windows + + + + + + + diff --git a/source/LookupEngine.Abstractions/Metadata/DecomposedMember.cs b/source/LookupEngine.Abstractions/Metadata/DecomposedMember.cs new file mode 100644 index 000000000..94af5535e --- /dev/null +++ b/source/LookupEngine.Abstractions/Metadata/DecomposedMember.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Enums; + +// ReSharper disable once CheckNamespace +namespace LookupEngine.Abstractions; + +[PublicAPI] +[DebuggerDisplay("Name = {Name} Value = {Value.Name}")] +public sealed class DecomposedMember +{ + public required int Depth { get; init; } + public required string Name { get; init; } + public required string DeclaringTypeName { get; init; } + public required string DeclaringTypeFullName { get; init; } + public double ComputationTime { get; init; } + public long AllocatedBytes { get; init; } + public MemberAttributes MemberAttributes { get; init; } + public required DecomposedValue Value { get; init; } +} \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Metadata/DecomposedObject.cs b/source/LookupEngine.Abstractions/Metadata/DecomposedObject.cs new file mode 100644 index 000000000..838c17cd3 --- /dev/null +++ b/source/LookupEngine.Abstractions/Metadata/DecomposedObject.cs @@ -0,0 +1,19 @@ +using System.Diagnostics; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Decomposition; + +// ReSharper disable once CheckNamespace +namespace LookupEngine.Abstractions; + +[PublicAPI] +[DebuggerDisplay("Name = {Name} Value = {RawValue}")] +public sealed class DecomposedObject +{ + public required object? RawValue { get; init; } + public required string Name { get; init; } + public required string TypeName { get; init; } + public required string TypeFullName { get; init; } + public string? Description { get; init; } + public Descriptor? Descriptor { get; init; } + public List Members { get; } = []; +} \ No newline at end of file diff --git a/source/LookupEngine.Abstractions/Metadata/DecomposedValue.cs b/source/LookupEngine.Abstractions/Metadata/DecomposedValue.cs new file mode 100644 index 000000000..110cd4f34 --- /dev/null +++ b/source/LookupEngine.Abstractions/Metadata/DecomposedValue.cs @@ -0,0 +1,18 @@ +using System.Diagnostics; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Decomposition; + +// ReSharper disable once CheckNamespace +namespace LookupEngine.Abstractions; + +[PublicAPI] +[DebuggerDisplay("Name = {Name} Value = {RawValue}")] +public sealed class DecomposedValue +{ + public required object? RawValue { get; init; } + public required string Name { get; init; } + public required string TypeName { get; init; } + public required string TypeFullName { get; init; } + public string? Description { get; init; } + public Descriptor? Descriptor { get; init; } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/BoolDescriptor.cs b/source/LookupEngine/Descriptors/BooleanDescriptor.cs similarity index 85% rename from source/RevitLookup/Core/ComponentModel/Descriptors/BoolDescriptor.cs rename to source/LookupEngine/Descriptors/BooleanDescriptor.cs index 1bfd003d8..49989a4cb 100644 --- a/source/RevitLookup/Core/ComponentModel/Descriptors/BoolDescriptor.cs +++ b/source/LookupEngine/Descriptors/BooleanDescriptor.cs @@ -18,11 +18,13 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.ComponentModel.Descriptors; +using LookupEngine.Abstractions.Decomposition; -public sealed class BoolDescriptor : Descriptor +namespace LookupEngine.Descriptors; + +public sealed class BooleanDescriptor : Descriptor { - public BoolDescriptor(bool value) + public BooleanDescriptor(bool value) { Name = value ? "True" : "False"; } diff --git a/source/LookupEngine/Descriptors/EnumerableDescriptor.cs b/source/LookupEngine/Descriptors/EnumerableDescriptor.cs new file mode 100644 index 000000000..9c217c90c --- /dev/null +++ b/source/LookupEngine/Descriptors/EnumerableDescriptor.cs @@ -0,0 +1,43 @@ +using System.Collections; +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Descriptors; + +public sealed class EnumerableDescriptor : Descriptor, IDescriptorEnumerator, IDescriptorResolver +{ + public EnumerableDescriptor(IEnumerable value) + { + Enumerator = value.GetEnumerator(); + + //Checking types to reduce memory allocation when creating an iterator and increase performance + IsEmpty = value switch + { + ICollection enumerable => enumerable.Count == 0, + _ => !Enumerator.MoveNext() + }; + + if (Enumerator is IDisposable disposable) + { + disposable.Dispose(); + } + } + + public IEnumerator Enumerator { get; } + public bool IsEmpty { get; } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(IEnumerable.GetEnumerator) => ResolveGetEnumerator, + _ => null + }; + + IVariant ResolveGetEnumerator() + { + return Variants.Empty(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ExceptionDescriptor.cs b/source/LookupEngine/Descriptors/ExceptionDescriptor.cs similarity index 94% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ExceptionDescriptor.cs rename to source/LookupEngine/Descriptors/ExceptionDescriptor.cs index 22e1ca84c..bbe478788 100644 --- a/source/RevitLookup/Core/ComponentModel/Descriptors/ExceptionDescriptor.cs +++ b/source/LookupEngine/Descriptors/ExceptionDescriptor.cs @@ -18,7 +18,9 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.ComponentModel.Descriptors; +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Descriptors; public sealed class ExceptionDescriptor : Descriptor { diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ObjectDescriptor.cs b/source/LookupEngine/Descriptors/ObjectDescriptor.cs similarity index 85% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ObjectDescriptor.cs rename to source/LookupEngine/Descriptors/ObjectDescriptor.cs index 37fac2806..9607aea3f 100644 --- a/source/RevitLookup/Core/ComponentModel/Descriptors/ObjectDescriptor.cs +++ b/source/LookupEngine/Descriptors/ObjectDescriptor.cs @@ -18,16 +18,14 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.ComponentModel.Descriptors; +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Descriptors; public sealed class ObjectDescriptor : Descriptor { - public ObjectDescriptor() - { - } - - public ObjectDescriptor(object value) + public ObjectDescriptor(object? value) { - Name = value.ToString(); + Name = value?.ToString(); } } \ No newline at end of file diff --git a/source/LookupEngine/Descriptors/StringDescriptor.cs b/source/LookupEngine/Descriptors/StringDescriptor.cs new file mode 100644 index 000000000..1a9432236 --- /dev/null +++ b/source/LookupEngine/Descriptors/StringDescriptor.cs @@ -0,0 +1,11 @@ +using LookupEngine.Abstractions.Decomposition; + +namespace LookupEngine.Descriptors; + +public sealed class StringDescriptor : Descriptor +{ + public StringDescriptor(string text) + { + Name = text; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Diagnostic/IEngineDiagnoser.cs b/source/LookupEngine/Diagnostic/IEngineDiagnoser.cs new file mode 100644 index 000000000..1bfa09f3c --- /dev/null +++ b/source/LookupEngine/Diagnostic/IEngineDiagnoser.cs @@ -0,0 +1,7 @@ +namespace LookupEngine.Diagnostic; + +public interface IEngineDiagnoser +{ + void StartMonitoring(); + void StopMonitoring(); +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Diagnostic/MemoryDiagnoser.cs b/source/LookupEngine/Diagnostic/MemoryDiagnoser.cs similarity index 92% rename from source/RevitLookup/Core/Diagnostic/MemoryDiagnoser.cs rename to source/LookupEngine/Diagnostic/MemoryDiagnoser.cs index d349346a5..388a50cdc 100644 --- a/source/RevitLookup/Core/Diagnostic/MemoryDiagnoser.cs +++ b/source/LookupEngine/Diagnostic/MemoryDiagnoser.cs @@ -18,33 +18,33 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Diagnostic; +namespace LookupEngine.Diagnostic; -public sealed class MemoryDiagnoser +public sealed class MemoryDiagnoser : IEngineDiagnoser { private long _initialAllocatedBytes; private long _finalAllocatedBytes; - - public void Start() + + public void StartMonitoring() { _initialAllocatedBytes = GetTotalAllocatedBytes(); } - - public void Stop() + + public void StopMonitoring() { _finalAllocatedBytes = GetTotalAllocatedBytes(); } - + public long GetAllocatedBytes() { var allocatedBytes = _finalAllocatedBytes - _initialAllocatedBytes; - + _finalAllocatedBytes = 0; _initialAllocatedBytes = 0; - + return allocatedBytes; } - + private static long GetTotalAllocatedBytes() { // Ref: https://github.com/dotnet/BenchmarkDotNet/blob/master/src/BenchmarkDotNet/Engines/GcStats.cs @@ -52,7 +52,7 @@ private static long GetTotalAllocatedBytes() // GC.GetTotalAllocatedBytes() depends heavily on the garbage collection and gives inaccurate results; // AppDomain.MonitoringIsEnabled almost does not see memory changes when methods are called. // GetAllocatedBytesForCurrentThread is the perfect choice for reflexion calls - + return GC.GetAllocatedBytesForCurrentThread(); } } \ No newline at end of file diff --git a/source/LookupEngine/Diagnostic/TimeDiagnoser.cs b/source/LookupEngine/Diagnostic/TimeDiagnoser.cs new file mode 100644 index 000000000..da509bd8e --- /dev/null +++ b/source/LookupEngine/Diagnostic/TimeDiagnoser.cs @@ -0,0 +1,53 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics; + +namespace LookupEngine.Diagnostic; + +public sealed class TimeDiagnoser : IEngineDiagnoser +{ + private long _startTimeStamp; + private long _endTimeStamp; + + public void StartMonitoring() + { + _startTimeStamp = Stopwatch.GetTimestamp(); + } + + public void StopMonitoring() + { + _endTimeStamp = Stopwatch.GetTimestamp(); + } + + public TimeSpan GetElapsed() + { +#if NETCOREAPP + var elapsed = Stopwatch.GetElapsedTime(_startTimeStamp, _endTimeStamp); +#else + var tickFrequency = (double) TimeSpan.TicksPerSecond / Stopwatch.Frequency; + var elapsed = new TimeSpan((long)((_endTimeStamp - _startTimeStamp) * tickFrequency)); +#endif + _startTimeStamp = 0; + _endTimeStamp = 0; + + return elapsed; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Enumeration.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.Enumeration.cs similarity index 81% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Enumeration.cs rename to source/LookupEngine/Engine/LookupComposer.Decomposition.Enumeration.cs index 0ca445060..d13f57179 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Enumeration.cs +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.Enumeration.cs @@ -20,22 +20,25 @@ using System.Collections; -namespace RevitLookup.Core.Engine; +// ReSharper disable once CheckNamespace +namespace LookupEngine; -public sealed partial class DescriptorBuilder +public partial class LookupComposer { private void AddEnumerableItems() { - if (_obj is not IEnumerable enumerable) return; - - _type = typeof(IEnumerable); + if (_input is not IEnumerable enumerable) return; + var enumerator = enumerable.GetEnumerator(); - + + var index = 0; while (enumerator.MoveNext()) { - WriteDescriptor(enumerator.Current); + WriteEnumerableMember(enumerator.Current, index); + index++; + _depth--; } - + if (enumerator is IDisposable disposable) { disposable.Dispose(); diff --git a/source/LookupEngine/Engine/LookupComposer.Decomposition.Events.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.Events.cs new file mode 100644 index 000000000..d1a72121a --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.Events.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using LookupEngine.Formaters; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private void DecomposeEvents(BindingFlags bindingFlags) + { + if (!_options.IncludeEvents) return; + + var members = MemberDeclaringType.GetEvents(bindingFlags); + foreach (var member in members) + { + WriteDecompositionMember(ReflexionFormater.FormatTypeName(member.EventHandlerType ?? typeof(object)), member); + } + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Decomposition.Fields.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.Fields.cs new file mode 100644 index 000000000..c2d7ef9db --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.Fields.cs @@ -0,0 +1,41 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private void DecomposeFields(BindingFlags bindingFlags) + { + if (!_options.IncludeFields) return; + + var members = MemberDeclaringType.GetFields(bindingFlags); + foreach (var member in members) + { + if (member.IsSpecialName) continue; + + var value = EvaluateValue(member); + WriteDecompositionMember(value, member); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Methods.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.Methods.cs similarity index 54% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Methods.cs rename to source/LookupEngine/Engine/LookupComposer.Decomposition.Methods.cs index 10598d1fc..a663e07db 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Methods.cs +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.Methods.cs @@ -19,31 +19,31 @@ // (Rights in Technical Data and Computer Software), as applicable. using System.Reflection; +using LookupEngine.Abstractions.Configuration; -namespace RevitLookup.Core.Engine; +// ReSharper disable once CheckNamespace +namespace LookupEngine; -public sealed partial class DescriptorBuilder +public partial class LookupComposer { - private void AddMethods(BindingFlags bindingFlags) + private void DecomposeMethods(BindingFlags bindingFlags) { - var members = _type.GetMethods(bindingFlags); + var members = MemberDeclaringType.GetMethods(bindingFlags); foreach (var member in members) { if (member.IsSpecialName) continue; - - object value; + if (member is {IsFamily: true, IsSecurityCritical: true}) continue; //Object-critical methods cause CLR exception + + object? value; var parameters = member.GetParameters(); - + try { if (!TryResolve(member, parameters, out value)) { - if (!IsMethodSupported(member, parameters, out value)) continue; - - if (value is null) - { - Evaluate(member, out value); - } + if (!TrySuppress(member, parameters, out value)) continue; + + value ??= EvaluateValue(member); } } catch (TargetInvocationException exception) @@ -54,68 +54,43 @@ private void AddMethods(BindingFlags bindingFlags) { value = exception; } - - WriteDescriptor(member, value, parameters); + + WriteDecompositionMember(value, member, parameters); } } - - private bool TryResolve(MethodInfo member, ParameterInfo[] parameters, out object value) + + private protected virtual bool TryResolve(MethodInfo member, ParameterInfo[] parameters, out object? value) { value = null; - if (_currentDescriptor is not IDescriptorResolver resolver) return false; - - var handler = resolver.Resolve(Context, member.Name, parameters); + if (MemberDeclaringDescriptor is not IDescriptorResolver resolver) return false; + + var handler = resolver.Resolve(member.Name, parameters); if (handler is null) return false; - - try - { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - value = handler.Invoke(); - } - finally - { - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); - } - + + value = EvaluateValue(handler); + return true; } - - private void Evaluate(MethodInfo member, out object value) - { - try - { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - value = member.Invoke(_obj, null); - } - finally - { - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); - } - } - - private bool IsMethodSupported(MethodInfo member, ParameterInfo[] parameters, out object value) + + private bool TrySuppress(MethodInfo member, ParameterInfo[] parameters, out object? value) { value = null; if (member.ReturnType.Name == "Void") { - if (!_settings.IncludeUnsupported) return false; - + if (!_options.IncludeUnsupported) return false; + value = new InvalidOperationException("Method doesn't return a value"); return true; } - + if (parameters.Length > 0) { - if (!_settings.IncludeUnsupported) return false; - + if (!_options.IncludeUnsupported) return false; + value = new NotSupportedException("Unsupported method overload"); return true; } - + return true; } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Properties.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.Properties.cs similarity index 55% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Properties.cs rename to source/LookupEngine/Engine/LookupComposer.Decomposition.Properties.cs index f7e8a07d6..48e3d9764 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Properties.cs +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.Properties.cs @@ -19,31 +19,32 @@ // (Rights in Technical Data and Computer Software), as applicable. using System.Reflection; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Configuration; -namespace RevitLookup.Core.Engine; +// ReSharper disable once CheckNamespace +namespace LookupEngine; -public sealed partial class DescriptorBuilder +[UsedImplicitly] +public partial class LookupComposer { - private void AddProperties(BindingFlags bindingFlags) + private void DecomposeProperties(BindingFlags bindingFlags) { - var members = _type.GetProperties(bindingFlags); + var members = MemberDeclaringType.GetProperties(bindingFlags); foreach (var member in members) { if (member.IsSpecialName) continue; - - object value; - var parameters = member.CanRead ? member.GetMethod!.GetParameters() : null; - + + object? value; + var parameters = member.CanRead ? member.GetMethod!.GetParameters() : []; + try { if (!TryResolve(member, parameters, out value)) { - if (!IsPropertySupported(member, parameters, out value)) continue; - - if (value is null) - { - Evaluate(member, out value); - } + if (!TrySuppress(member, parameters, out value)) continue; + + value ??= EvaluateValue(member); } } catch (TargetInvocationException exception) @@ -54,67 +55,42 @@ private void AddProperties(BindingFlags bindingFlags) { value = exception; } - - WriteDescriptor(member, value, parameters); + + WriteDecompositionMember(value, member, parameters); } } - - private bool TryResolve(PropertyInfo member, ParameterInfo[] parameters, out object value) + + private protected virtual bool TryResolve(PropertyInfo member, ParameterInfo[] parameters, out object? value) { value = null; - if (_currentDescriptor is not IDescriptorResolver resolver) return false; - - var handler = resolver.Resolve(Context, member.Name, parameters); + if (MemberDeclaringDescriptor is not IDescriptorResolver resolver) return false; + + var handler = resolver.Resolve(member.Name, parameters); if (handler is null) return false; - - try - { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - value = handler.Invoke(); - } - finally - { - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); - } - + + value = EvaluateValue(handler); + return true; } - - private void Evaluate(PropertyInfo member, out object value) - { - try - { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - value = member.GetValue(_obj); - } - finally - { - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); - } - } - - private bool IsPropertySupported(PropertyInfo member, ParameterInfo[] parameters, out object value) + + private bool TrySuppress(PropertyInfo member, ParameterInfo[] parameters, out object? value) { value = null; - + if (!member.CanRead) { value = new InvalidOperationException("Property does not have a get accessor, it cannot be read"); return true; } - + if (parameters.Length > 0) { - if (!_settings.IncludeUnsupported) return false; - + if (!_options.IncludeUnsupported) return false; + value = new NotSupportedException("Unsupported property overload"); return true; } - + return true; } } \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Decomposition.cs b/source/LookupEngine/Engine/LookupComposer.Decomposition.cs new file mode 100644 index 000000000..a234c29a2 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Decomposition.cs @@ -0,0 +1,141 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics.Contracts; +using System.Reflection; +using LookupEngine.Abstractions; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + [Pure] + private DecomposedObject DecomposeInstance() + { + _decomposedObject = DecomposeInstanceObject(); + var objectType = _input.GetType(); + var members = DecomposeInstanceMembers(objectType); + _decomposedObject.Members.AddRange(members); + + return _decomposedObject; + } + + [Pure] + private DecomposedObject DecomposeInstanceObject() + { + _input = RedirectValue(_input, out var instanceDescriptor); + + var objectType = _input.GetType(); + return CreateInstanceDecomposition(_input, objectType, instanceDescriptor); + } + + [Pure] + private DecomposedObject DecomposeStatic(Type type) + { + _decomposedObject = DecomposeStaticObject(type); + var members = DecomposeStaticMembers(type); + _decomposedObject.Members.AddRange(members); + + return _decomposedObject; + } + + [Pure] + private DecomposedObject DecomposeStaticObject(Type type) + { + var staticDescriptor = _options.TypeResolver.Invoke(null, type); + return CreateStaticDecomposition(type, staticDescriptor); + } + + [Pure] + private List DecomposeInstanceMembers() + { + return DecomposeInstanceMembers(_input.GetType()); + } + + [Pure] + private List DecomposeInstanceMembers(Type objectType) + { + _decomposedMembers = new List(32); + + var objectTypeHierarchy = GetTypeHierarchy(objectType); + for (var i = objectTypeHierarchy.Count - 1; i >= 0; i--) + { + MemberDeclaringType = objectTypeHierarchy[i]; + MemberDeclaringDescriptor = _options.TypeResolver.Invoke(_input, MemberDeclaringType); + + var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + if (_options.IncludeStaticMembers) flags |= BindingFlags.Static; + if (_options.IncludePrivateMembers) flags |= BindingFlags.NonPublic; + + DecomposeFields(flags); + DecomposeProperties(flags); + DecomposeMethods(flags); + DecomposeEvents(flags); + ExecuteExtensions(); + + _depth--; + } + + MemberDeclaringType = objectType; + AddEnumerableItems(); + + return _decomposedMembers; + } + + [Pure] + private List DecomposeStaticMembers(Type objectType) + { + _decomposedMembers = new List(32); + + var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + if (_options.IncludePrivateMembers) flags |= BindingFlags.NonPublic; + + var objectTypeHierarchy = GetTypeHierarchy(objectType); + for (var i = objectTypeHierarchy.Count - 1; i >= 0; i--) + { + MemberDeclaringType = objectTypeHierarchy[i]; + MemberDeclaringDescriptor = _options.TypeResolver.Invoke(null, MemberDeclaringType); + + DecomposeFields(flags); + DecomposeProperties(flags); + DecomposeMethods(flags); + + _depth--; + } + + return _decomposedMembers; + } + + [Pure] + private List GetTypeHierarchy(Type inputType) + { + var types = new List(); + while (inputType.BaseType is not null) + { + types.Add(inputType); + inputType = inputType.BaseType; + } + + if (_options.IncludeRoot) types.Add(inputType); + + return types; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Diagnostic.cs b/source/LookupEngine/Engine/LookupComposer.Diagnostic.cs new file mode 100644 index 000000000..d025c9c35 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Diagnostic.cs @@ -0,0 +1,93 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Diagnostic; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private protected readonly TimeDiagnoser TimeDiagnoser = new(); + private protected readonly MemoryDiagnoser MemoryDiagnoser = new(); + + private object? EvaluateValue(FieldInfo member) + { + TimeDiagnoser.StartMonitoring(); + MemoryDiagnoser.StartMonitoring(); + + var value = member.GetValue(_input); + + MemoryDiagnoser.StopMonitoring(); + TimeDiagnoser.StopMonitoring(); + + return value; + } + + private object? EvaluateValue(PropertyInfo member) + { + try + { + TimeDiagnoser.StartMonitoring(); + MemoryDiagnoser.StartMonitoring(); + + return member.GetValue(_input); + } + finally + { + MemoryDiagnoser.StopMonitoring(); + TimeDiagnoser.StopMonitoring(); + } + } + + private object? EvaluateValue(MethodInfo member) + { + try + { + TimeDiagnoser.StartMonitoring(); + MemoryDiagnoser.StartMonitoring(); + + return member.Invoke(_input, null); + } + finally + { + MemoryDiagnoser.StopMonitoring(); + TimeDiagnoser.StopMonitoring(); + } + } + + private protected IVariant EvaluateValue(Func handler) + { + try + { + TimeDiagnoser.StartMonitoring(); + MemoryDiagnoser.StartMonitoring(); + + return handler.Invoke(); + } + finally + { + MemoryDiagnoser.StopMonitoring(); + TimeDiagnoser.StopMonitoring(); + } + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Features.Extensions.cs b/source/LookupEngine/Engine/LookupComposer.Features.Extensions.cs new file mode 100644 index 000000000..8b5f01ab4 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Features.Extensions.cs @@ -0,0 +1,51 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +//ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer : IExtensionManager +{ + private protected virtual void ExecuteExtensions() + { + if (!_options.EnableExtensions) return; + + if (MemberDeclaringDescriptor is IDescriptorExtension extension) + { + extension.RegisterExtensions(this); + } + } + + public void Register(string methodName, Func handler) + { + try + { + var result = EvaluateValue(handler); + WriteExtensionMember(result, methodName); + } + catch (Exception exception) + { + WriteExtensionMember(exception, methodName); + } + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Features.Redirection.cs b/source/LookupEngine/Engine/LookupComposer.Features.Redirection.cs new file mode 100644 index 000000000..0615d6713 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Features.Redirection.cs @@ -0,0 +1,81 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private protected virtual object RedirectValue(object value) + { + if (!_options.EnableRedirection) return value; + + var valueDescriptor = _options.TypeResolver.Invoke(value, null); + while (valueDescriptor is IDescriptorRedirector redirector) + { + if (!redirector.TryRedirect(string.Empty, out value)) break; + valueDescriptor = _options.TypeResolver.Invoke(value, null); + } + + return value; + } + + private object RedirectValue(object value, out Descriptor valueDescriptor) + { + return RedirectValue(value, string.Empty, out valueDescriptor); + } + + private protected virtual object RedirectValue(object value, string target, out Descriptor valueDescriptor) + { + var variant = value as IVariant; + if (variant is not null) + { + value = variant.Value; + } + + valueDescriptor = _options.TypeResolver.Invoke(value, null); + + var description = valueDescriptor.Description; + if (variant is not null && description is null) + { + description = variant.Description; + } + + if (_options.EnableRedirection) + { + while (valueDescriptor is IDescriptorRedirector redirector) + { + if (!redirector.TryRedirect(target, out value)) break; + valueDescriptor = _options.TypeResolver.Invoke(value, null); + + if (valueDescriptor.Description is not null) + { + description = valueDescriptor.Description; + } + } + } + + valueDescriptor.Description = description; + return value; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Settings.cs b/source/LookupEngine/Engine/LookupComposer.Settings.cs new file mode 100644 index 000000000..f535b93a2 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Settings.cs @@ -0,0 +1,88 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using JetBrains.Annotations; +using LookupEngine.Abstractions; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Exceptions; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +[PublicAPI] +public partial class LookupComposer +{ + private readonly DecomposeOptions _options; + + private int _depth; + private object _input; + private Type? _memberDeclaringType; + private Descriptor? _memberDeclaringDescriptor; + private DecomposedObject? _decomposedObject; + private List? _decomposedMembers; + + private protected LookupComposer(object value, DecomposeOptions options) + { + _input = value; + _options = options; + } + + internal List DecomposedMembers + { + get + { + if (_decomposedMembers is null) + { + EngineException.ThrowIfEngineNotInitialized(nameof(DecomposedMembers)); + } + + return _decomposedMembers; + } + set => _decomposedMembers = value; + } + + internal Type MemberDeclaringType + { + get + { + if (_memberDeclaringType is null) + { + EngineException.ThrowIfEngineNotInitialized(nameof(MemberDeclaringType)); + } + + return _memberDeclaringType; + } + set => _memberDeclaringType = value; + } + + internal Descriptor MemberDeclaringDescriptor + { + get + { + if (_memberDeclaringDescriptor is null) + { + EngineException.ThrowIfEngineNotInitialized(nameof(MemberDeclaringDescriptor)); + } + + return _memberDeclaringDescriptor; + } + set => _memberDeclaringDescriptor = value; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.Writer.cs b/source/LookupEngine/Engine/LookupComposer.Writer.cs new file mode 100644 index 000000000..aeaa98016 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.Writer.cs @@ -0,0 +1,185 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using System.Reflection; +using LookupEngine.Abstractions; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Abstractions.Enums; +using LookupEngine.Formaters; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private protected static DecomposedObject CreateNullableDecomposition() + { + return new DecomposedObject + { + Name = $"{nameof(System)}.{nameof(Object)}", + RawValue = null, + TypeName = nameof(Object), + TypeFullName = $"{nameof(System)}.{nameof(Object)}" + }; + } + + private static DecomposedObject CreateInstanceDecomposition(object instance, Type type, Descriptor descriptor) + { + var formatTypeName = ReflexionFormater.FormatTypeName(type); + var hasUnknownName = descriptor.Name is null || + type.Namespace is null || + descriptor.Name!.StartsWith(type.Namespace, StringComparison.OrdinalIgnoreCase); + + return new DecomposedObject + { + Name = hasUnknownName ? formatTypeName : descriptor.Name!, + Description = descriptor.Description, + RawValue = instance, + TypeName = formatTypeName, + TypeFullName = $"{type.Namespace}.{formatTypeName}", + Descriptor = descriptor + }; + } + + private static DecomposedObject CreateStaticDecomposition(Type type, Descriptor descriptor) + { + var formatTypeName = ReflexionFormater.FormatTypeName(type); + var hasUnknownName = descriptor.Name is null || + type.Namespace is null || + descriptor.Name!.StartsWith(type.Namespace, StringComparison.OrdinalIgnoreCase); + + return new DecomposedObject + { + Name = hasUnknownName ? formatTypeName : descriptor.Name!, + Description = descriptor.Description, + RawValue = type, + TypeName = formatTypeName, + TypeFullName = $"{type.Namespace}.{formatTypeName}", + Descriptor = descriptor + }; + } + + private void WriteEnumerableMember(object? value, int index) + { + var member = new DecomposedMember + { + Depth = _depth, + Value = CreateValue(nameof(IEnumerable), value), + Name = $"{ReflexionFormater.FormatTypeName(MemberDeclaringType).Replace("[]", string.Empty)}[{index}]", + MemberAttributes = MemberAttributes.Property, + DeclaringTypeName = nameof(IEnumerable), + DeclaringTypeFullName = $"{nameof(System)}.{nameof(System.Collections)}.{nameof(IEnumerable)}", + }; + + DecomposedMembers.Add(member); + } + + private protected void WriteExtensionMember(object? value, string name) + { + var formatTypeName = ReflexionFormater.FormatTypeName(MemberDeclaringType); + + var member = new DecomposedMember + { + Depth = _depth, + Name = name, + Value = CreateValue(name, value), + DeclaringTypeName = formatTypeName, + DeclaringTypeFullName = $"{MemberDeclaringType.Namespace}.{formatTypeName}", + MemberAttributes = MemberAttributes.Extension, + ComputationTime = TimeDiagnoser.GetElapsed().TotalMilliseconds, + AllocatedBytes = MemoryDiagnoser.GetAllocatedBytes() + }; + + DecomposedMembers.Add(member); + } + + private void WriteDecompositionMember(object? value, MemberInfo memberInfo) + { + var formatTypeName = ReflexionFormater.FormatTypeName(MemberDeclaringType); + + var member = new DecomposedMember + { + Depth = _depth, + Value = CreateValue(memberInfo.Name, value), + Name = memberInfo.Name, + DeclaringTypeName = formatTypeName, + DeclaringTypeFullName = $"{MemberDeclaringType.Namespace}.{formatTypeName}", + MemberAttributes = ModifiersFormater.FormatAttributes(memberInfo), + ComputationTime = TimeDiagnoser.GetElapsed().TotalMilliseconds, + AllocatedBytes = MemoryDiagnoser.GetAllocatedBytes() + }; + + DecomposedMembers.Add(member); + } + + private void WriteDecompositionMember(object? value, MemberInfo memberInfo, ParameterInfo[] parameters) + { + var formatTypeName = ReflexionFormater.FormatTypeName(MemberDeclaringType); + + var member = new DecomposedMember + { + Depth = _depth, + Value = CreateValue(memberInfo.Name, value), + Name = ReflexionFormater.FormatMemberName(memberInfo, parameters), + DeclaringTypeName = formatTypeName, + DeclaringTypeFullName = $"{MemberDeclaringType.Namespace}.{formatTypeName}", + MemberAttributes = ModifiersFormater.FormatAttributes(memberInfo), + ComputationTime = TimeDiagnoser.GetElapsed().TotalMilliseconds, + AllocatedBytes = MemoryDiagnoser.GetAllocatedBytes() + }; + + DecomposedMembers.Add(member); + } + + private DecomposedValue CreateNullableValue() + { + return new DecomposedValue + { + RawValue = null, + Name = string.Empty, + TypeName = nameof(Object), + TypeFullName = $"{nameof(System)}.{nameof(Object)}" + }; + } + + private DecomposedValue CreateValue(string targetMember, object? value) + { + if (value is null) return CreateNullableValue(); + + value = RedirectValue(value, targetMember, out var valueDescriptor); + + var valueType = value.GetType(); + var formatTypeName = ReflexionFormater.FormatTypeName(valueType); + var hasUnknownName = valueDescriptor.Name is null || + valueType.Namespace is null || + valueDescriptor.Name.StartsWith(valueType.Namespace, StringComparison.OrdinalIgnoreCase); + + return new DecomposedValue + { + RawValue = value, + Name = hasUnknownName ? formatTypeName : valueDescriptor.Name!, + Description = valueDescriptor.Description, + TypeName = formatTypeName, + TypeFullName = $"{valueType.Namespace}.{formatTypeName}", + Descriptor = valueDescriptor + }; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer.cs b/source/LookupEngine/Engine/LookupComposer.cs new file mode 100644 index 000000000..26231a79c --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer.cs @@ -0,0 +1,67 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using JetBrains.Annotations; +using LookupEngine.Abstractions; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + [Pure] + public static DecomposedObject Decompose(object? value, DecomposeOptions? options = null) + { + if (value is null) return CreateNullableDecomposition(); + + options ??= DecomposeOptions.Default; + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStatic(type), + _ => new LookupComposer(value, options).DecomposeInstance() + }; + } + + [Pure] + public static DecomposedObject DecomposeObject(object? value, DecomposeOptions? options = null) + { + if (value is null) return CreateNullableDecomposition(); + + options ??= DecomposeOptions.Default; + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStaticObject(type), + _ => new LookupComposer(value, options).DecomposeInstanceObject() + }; + } + + [Pure] + public static List DecomposeMembers(object? value, DecomposeOptions? options = null) + { + if (value is null) return []; + + options ??= DecomposeOptions.Default; + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStaticMembers(type), + _ => new LookupComposer(value, options).DecomposeInstanceMembers() + }; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Methods.cs b/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Methods.cs new file mode 100644 index 000000000..52ba52f4b --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Methods.cs @@ -0,0 +1,55 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private protected override bool TryResolve(MethodInfo member, ParameterInfo[] parameters, out object? value) + { + value = null; + + if (MemberDeclaringDescriptor is IDescriptorResolver resolver) + { + var handler = resolver.Resolve(member.Name, parameters); + if (handler is not null) + { + value = EvaluateValue(handler); + return true; + } + } + + if (MemberDeclaringDescriptor is IDescriptorResolver contextResolver) + { + var handler = contextResolver.Resolve(member.Name, parameters); + if (handler is not null) + { + value = EvaluateValue(handler); + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Properties.cs b/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Properties.cs new file mode 100644 index 000000000..8818ac626 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.Decomposition.Properties.cs @@ -0,0 +1,57 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Configuration; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +[UsedImplicitly] +public partial class LookupComposer +{ + private protected override bool TryResolve(PropertyInfo member, ParameterInfo[] parameters, out object? value) + { + value = null; + + if (MemberDeclaringDescriptor is IDescriptorResolver resolver) + { + var handler = resolver.Resolve(member.Name, parameters); + if (handler is not null) + { + value = EvaluateValue(handler); + return true; + } + } + + if (MemberDeclaringDescriptor is IDescriptorResolver contextResolver) + { + var handler = contextResolver.Resolve(member.Name, parameters); + if (handler is not null) + { + value = EvaluateValue(handler); + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.Diagnostic.cs b/source/LookupEngine/Engine/LookupComposer{T}.Diagnostic.cs new file mode 100644 index 000000000..a70f4d596 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.Diagnostic.cs @@ -0,0 +1,43 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Decomposition; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private IVariant EvaluateValue(Func handler) + { + try + { + TimeDiagnoser.StartMonitoring(); + MemoryDiagnoser.StartMonitoring(); + + return handler.Invoke(_options.Context); + } + finally + { + MemoryDiagnoser.StopMonitoring(); + TimeDiagnoser.StopMonitoring(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Extensions.cs b/source/LookupEngine/Engine/LookupComposer{T}.Features.Extensions.cs similarity index 57% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Extensions.cs rename to source/LookupEngine/Engine/LookupComposer{T}.Features.Extensions.cs index 157aedc03..abb6301e0 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Extensions.cs +++ b/source/LookupEngine/Engine/LookupComposer{T}.Features.Extensions.cs @@ -18,43 +18,39 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Engine; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; -public sealed partial class DescriptorBuilder : IExtensionManager +//ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer : IExtensionManager { - private void AddExtensions() - { - if (!_settings.IncludeExtensions) return; - if (_currentDescriptor is not IDescriptorExtension extension) return; - - extension.RegisterExtensions(this); - } - - public void Register(string methodName, Func handler) + private protected override void ExecuteExtensions() { - try + if (!_options.EnableExtensions) return; + + if (MemberDeclaringDescriptor is IDescriptorExtension extension) { - var result = Evaluate(handler); - WriteDescriptor(methodName, result); + extension.RegisterExtensions(this); } - catch (Exception exception) + + if (MemberDeclaringDescriptor is IDescriptorExtension contextExtension) { - WriteDescriptor(methodName, exception); + contextExtension.RegisterExtensions(this); } } - - private object Evaluate(Func handler) + + public void Register(string name, Func extension) { try { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - return handler.Invoke(Context); + var result = EvaluateValue(extension); + WriteExtensionMember(result, name); } - finally + catch (Exception exception) { - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); + WriteExtensionMember(exception, name); } } } \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.Features.Redirection.cs b/source/LookupEngine/Engine/LookupComposer{T}.Features.Redirection.cs new file mode 100644 index 000000000..5042774a8 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.Features.Redirection.cs @@ -0,0 +1,114 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + private protected override object RedirectValue(object value) + { + if (!_options.EnableRedirection) return value; + + var valueDescriptor = _options.TypeResolver.Invoke(value, null); + while (true) + { + var redirected = false; + + // Generic interface is prioritised + if (valueDescriptor is IDescriptorRedirector genericRedirector) + { + if (genericRedirector.TryRedirect(string.Empty, _options.Context, out value)) + { + redirected = true; + } + } + else if (valueDescriptor is IDescriptorRedirector redirector) + { + if (redirector.TryRedirect(string.Empty, out value)) + { + redirected = true; + } + } + + if (!redirected) break; + + valueDescriptor = _options.TypeResolver.Invoke(value, null); + } + + return value; + } + + private protected override object RedirectValue(object value, string target, out Descriptor valueDescriptor) + { + var variant = value as IVariant; + if (variant is not null) + { + value = variant.Value; + } + + valueDescriptor = _options.TypeResolver.Invoke(value, null); + + var description = valueDescriptor.Description; + if (variant is not null && description is null) + { + description = variant.Description; + } + + if (_options.EnableRedirection) + { + while (true) + { + var redirected = false; + + // Generic interface is prioritised + if (valueDescriptor is IDescriptorRedirector genericRedirector) + { + if (genericRedirector.TryRedirect(target, _options.Context, out value)) + { + redirected = true; + } + } + else if (valueDescriptor is IDescriptorRedirector redirector) + { + if (redirector.TryRedirect(target, out value)) + { + redirected = true; + } + } + + if (!redirected) break; + + valueDescriptor = _options.TypeResolver.Invoke(value, null); + + if (valueDescriptor.Description is not null) + { + description = valueDescriptor.Description; + } + } + } + + valueDescriptor.Description = description; + return value; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.Settings.cs b/source/LookupEngine/Engine/LookupComposer{T}.Settings.cs new file mode 100644 index 000000000..9be118809 --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.Settings.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using LookupEngine.Options; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +[PublicAPI] +public sealed partial class LookupComposer : LookupComposer +{ + private readonly DecomposeOptions _options; + + internal LookupComposer(object value, DecomposeOptions options) : base(value, options) + { + _options = options; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Engine/LookupComposer{T}.cs b/source/LookupEngine/Engine/LookupComposer{T}.cs new file mode 100644 index 000000000..4bffc374c --- /dev/null +++ b/source/LookupEngine/Engine/LookupComposer{T}.cs @@ -0,0 +1,65 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using JetBrains.Annotations; +using LookupEngine.Abstractions; +using LookupEngine.Options; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +public partial class LookupComposer +{ + [Pure] + public static DecomposedObject Decompose(object? value, DecomposeOptions options) + { + if (value is null) return CreateNullableDecomposition(); + + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStatic(type), + _ => new LookupComposer(value, options).DecomposeInstance() + }; + } + + [Pure] + public static DecomposedObject DecomposeObject(object? value, DecomposeOptions options) + { + if (value is null) return CreateNullableDecomposition(); + + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStaticObject(type), + _ => new LookupComposer(value, options).DecomposeInstanceObject() + }; + } + + [Pure] + public static List DecomposeMembers(object? value, DecomposeOptions options) + { + if (value is null) return []; + + return value switch + { + Type type => new LookupComposer(value, options).DecomposeStaticMembers(type), + _ => new LookupComposer(value, options).DecomposeInstanceMembers() + }; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Exceptions/EngineException.cs b/source/LookupEngine/Exceptions/EngineException.cs new file mode 100644 index 000000000..956fe53bd --- /dev/null +++ b/source/LookupEngine/Exceptions/EngineException.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; + +namespace LookupEngine.Exceptions; + +public sealed class EngineException(string message) : Exception(message) +{ + [DoesNotReturn] + internal static void ThrowIfEngineNotInitialized(string propertyName) + { + throw new EngineException($"LookupEngine internal error. {propertyName} must be initialized before accessing it."); + } +} \ No newline at end of file diff --git a/source/LookupEngine/Formaters/ModifiersFormater.cs b/source/LookupEngine/Formaters/ModifiersFormater.cs new file mode 100644 index 000000000..2c765ef37 --- /dev/null +++ b/source/LookupEngine/Formaters/ModifiersFormater.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using LookupEngine.Abstractions.Enums; + +namespace LookupEngine.Formaters; + +internal static class ModifiersFormater +{ + internal static MemberAttributes FormatAttributes(MemberInfo member) + { + return member switch + { + MethodInfo info => CombineModifiers(MemberAttributes.Method, info.Attributes), + PropertyInfo info => CombineModifiers(MemberAttributes.Property, info.CanRead ? info.GetMethod!.Attributes : info.SetMethod!.Attributes), + FieldInfo info => CombineModifiers(MemberAttributes.Field, info.Attributes), + EventInfo info => CombineModifiers(MemberAttributes.Event, info.AddMethod!.Attributes), + _ => throw new ArgumentOutOfRangeException(nameof(member)) + }; + } + + private static MemberAttributes CombineModifiers(MemberAttributes attributes, MethodAttributes methodAttributes) + { + if ((methodAttributes & MethodAttributes.Static) != 0) attributes |= MemberAttributes.Static; + if ((methodAttributes & MethodAttributes.Private) != 0) attributes |= MemberAttributes.Private; + return attributes; + } + + private static MemberAttributes CombineModifiers(MemberAttributes attributes, FieldAttributes fieldAttributes) + { + if ((fieldAttributes & FieldAttributes.Static) != 0) attributes |= MemberAttributes.Static; + if ((fieldAttributes & FieldAttributes.Private) != 0) attributes |= MemberAttributes.Private; + return attributes; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Formaters/ReflexionFormater.cs b/source/LookupEngine/Formaters/ReflexionFormater.cs new file mode 100644 index 000000000..bf08fa184 --- /dev/null +++ b/source/LookupEngine/Formaters/ReflexionFormater.cs @@ -0,0 +1,41 @@ +using System.Reflection; + +namespace LookupEngine.Formaters; + +internal static class ReflexionFormater +{ + public static string FormatTypeName(Type type) + { + if (!type.IsGenericType) return type.Name; + + var typeName = type.Name; + var apostropheIndex = typeName.IndexOf('`'); + if (apostropheIndex > 0) typeName = typeName[..apostropheIndex]; + typeName += "<"; + var genericArguments = type.GetGenericArguments(); + for (var i = 0; i < genericArguments.Length; i++) + { + typeName += FormatTypeName(genericArguments[i]); + if (i < genericArguments.Length - 1) typeName += ", "; + } + + typeName += ">"; + return typeName; + } + + public static string FormatMemberName(MemberInfo member, ParameterInfo[] parameters) + { + if (parameters.Length == 0) return member.Name; + + var formatedParameters = parameters.Select(info => + { + return info.ParameterType.IsByRef switch + { + true => $"ref {FormatTypeName(info.ParameterType).Replace("&", string.Empty)}", + false => FormatTypeName(info.ParameterType) + }; + }); + + return $"{member.Name} ({string.Join(", ", formatedParameters)})"; + } +} \ No newline at end of file diff --git a/source/LookupEngine/LookupEngine.csproj b/source/LookupEngine/LookupEngine.csproj new file mode 100644 index 000000000..a274d52fb --- /dev/null +++ b/source/LookupEngine/LookupEngine.csproj @@ -0,0 +1,11 @@ + + + + net48;net8.0-windows + + + + + + + diff --git a/source/LookupEngine/Options/DecomposeOptions.cs b/source/LookupEngine/Options/DecomposeOptions.cs new file mode 100644 index 000000000..092642ecf --- /dev/null +++ b/source/LookupEngine/Options/DecomposeOptions.cs @@ -0,0 +1,42 @@ +using System.Collections; +using JetBrains.Annotations; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Descriptors; + +// ReSharper disable once CheckNamespace +namespace LookupEngine; + +[PublicAPI] +public class DecomposeOptions +{ + private Func? _typeResolver; + + public bool IncludeRoot { get; set; } + public bool IncludeFields { get; set; } + public bool IncludeEvents { get; set; } + public bool IncludeUnsupported { get; set; } + public bool IncludePrivateMembers { get; set; } + public bool IncludeStaticMembers { get; set; } + public bool EnableExtensions { get; set; } + public bool EnableRedirection { get; set; } + + public Func TypeResolver + { + get { return _typeResolver ??= DefaultResolveMap; } + set => _typeResolver = value; + } + + public static DecomposeOptions Default => new(); + + private static Descriptor DefaultResolveMap(object? obj, Type? type) + { + return obj switch + { + bool value when type is null || type == typeof(bool) => new BooleanDescriptor(value), + string value when type is null || type == typeof(string) => new StringDescriptor(value), + IEnumerable value => new EnumerableDescriptor(value), + Exception value when type is null || type == typeof(Exception) => new ExceptionDescriptor(value), + _ => new ObjectDescriptor(obj) + }; + } +} \ No newline at end of file diff --git a/source/LookupEngine/Options/DecomposeOptions{T}.cs b/source/LookupEngine/Options/DecomposeOptions{T}.cs new file mode 100644 index 000000000..4356bf93a --- /dev/null +++ b/source/LookupEngine/Options/DecomposeOptions{T}.cs @@ -0,0 +1,9 @@ +using JetBrains.Annotations; + +namespace LookupEngine.Options; + +[PublicAPI] +public class DecomposeOptions : DecomposeOptions +{ + public required TContext Context { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Contracts/IDescriptorConnector.cs b/source/RevitLookup.Abstractions/Configuration/IContextMenuConnector.cs similarity index 86% rename from source/RevitLookup/Core/Contracts/IDescriptorConnector.cs rename to source/RevitLookup.Abstractions/Configuration/IContextMenuConnector.cs index e8369e2f8..37536a07d 100644 --- a/source/RevitLookup/Core/Contracts/IDescriptorConnector.cs +++ b/source/RevitLookup.Abstractions/Configuration/IContextMenuConnector.cs @@ -20,12 +20,12 @@ using System.Windows.Controls; -namespace RevitLookup.Core.Contracts; +namespace RevitLookup.Abstractions.Configuration; /// /// Indicates that additional members can be added to the descriptor /// -public interface IDescriptorConnector +public interface IContextMenuConnector { - void RegisterMenu(ContextMenu contextMenu); + void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider); } \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/AboutProgram/OpenSourceSoftware.cs b/source/RevitLookup.Abstractions/Models/AboutProgram/OpenSourceSoftware.cs new file mode 100644 index 000000000..84d394f42 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/AboutProgram/OpenSourceSoftware.cs @@ -0,0 +1,9 @@ +namespace RevitLookup.Abstractions.Models.AboutProgram; + +public sealed class OpenSourceSoftware +{ + public required string SoftwareName { get; set; } + public required string SoftwareUri { get; set; } + public required string LicenseName { get; set; } + public required string LicenseUri { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/Decomposition/KnownDecompositionObject.cs b/source/RevitLookup.Abstractions/Models/Decomposition/KnownDecompositionObject.cs new file mode 100644 index 000000000..c2a13de9b --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/Decomposition/KnownDecompositionObject.cs @@ -0,0 +1,23 @@ +namespace RevitLookup.Abstractions.Models.Decomposition; + +public enum KnownDecompositionObject +{ + View, + Document, + Application, + UiApplication, + UiControlledApplication, + Database, + DependentElements, + Selection, + Face, + Edge, + Point, + SubElement, + LinkedElement, + ComponentManager, + PerformanceAdviser, + UpdaterRegistry, + Services, + Schemas +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/EventArgs/EventInfoArgs.cs b/source/RevitLookup.Abstractions/Models/EventArgs/EventInfoArgs.cs new file mode 100644 index 000000000..b13df9573 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/EventArgs/EventInfoArgs.cs @@ -0,0 +1,7 @@ +namespace RevitLookup.Abstractions.Models.EventArgs; + +public sealed class EventInfoArgs +{ + public required string EventName { get; set; } + public required object Arguments { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/GitHub/GitHubResponse.cs b/source/RevitLookup.Abstractions/Models/GitHub/GitHubResponse.cs new file mode 100644 index 000000000..18b6ca9a7 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/GitHub/GitHubResponse.cs @@ -0,0 +1,34 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Text.Json.Serialization; + +namespace RevitLookup.Abstractions.Models.GitHub; + +[Serializable] +public sealed class GitHubResponse +{ + [JsonPropertyName("html_url")] public string? Url { get; set; } + [JsonPropertyName("tag_name")] public string? TagName { get; set; } + [JsonPropertyName("draft")] public bool Draft { get; set; } + [JsonPropertyName("prerelease")] public bool PreRelease { get; set; } + [JsonPropertyName("published_at")] public DateTimeOffset PublishedDate { get; set; } + [JsonPropertyName("assets")] public List? Assets { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/GitHub/GutHubResponseAsset.cs b/source/RevitLookup.Abstractions/Models/GitHub/GutHubResponseAsset.cs new file mode 100644 index 000000000..227793df9 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/GitHub/GutHubResponseAsset.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace RevitLookup.Abstractions.Models.GitHub; + +[Serializable] +public sealed class GutHubResponseAsset +{ + [JsonPropertyName("name")] public string? Name { get; set; } + [JsonPropertyName("browser_download_url")] public string? DownloadUrl { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/Settings/GeneralSettings.cs b/source/RevitLookup.Abstractions/Models/Settings/GeneralSettings.cs new file mode 100644 index 000000000..ba955255f --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/Settings/GeneralSettings.cs @@ -0,0 +1,31 @@ +using System.Text.Json.Serialization; +using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace RevitLookup.Abstractions.Models.Settings; + +[Serializable] +public sealed class GeneralSettings +{ + [JsonPropertyName("Theme")] public ApplicationTheme Theme { get; set; } + [JsonPropertyName("Background")] public WindowBackdropType Background { get; set; } + [JsonPropertyName("Transition")] public Transition Transition { get; set; } + + [JsonPropertyName("WindowWidth")] public double WindowWidth { get; set; } + [JsonPropertyName("WindowHeight")] public double WindowHeight { get; set; } + + [JsonPropertyName("IsPrivateAllowed")] public bool IncludePrivate { get; set; } + [JsonPropertyName("IsFieldsAllowed")] public bool IncludeFields { get; set; } + [JsonPropertyName("IsStaticAllowed")] public bool IncludeStatic { get; set; } + [JsonPropertyName("IsEventsAllowed")] public bool IncludeEvents { get; set; } + [JsonPropertyName("IsExtensionsAllowed")] public bool IncludeExtensions { get; set; } + [JsonPropertyName("IsUnsupportedAllowed")] public bool IncludeUnsupported { get; set; } + [JsonPropertyName("IsRootHierarchyAllowed")] public bool IncludeRootHierarchy { get; set; } + + [JsonPropertyName("IsHardwareRenderingAllowed")] public bool UseHardwareRendering { get; set; } + [JsonPropertyName("IsTimeColumnAllowed")] public bool ShowTimeColumn { get; set; } + [JsonPropertyName("ShowMemoryColumn")] public bool ShowMemoryColumn { get; set; } + [JsonPropertyName("UseSizeRestoring")] public bool UseSizeRestoring { get; set; } + [JsonPropertyName("IsModifyTabAllowed")] public bool UseModifyTab { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/Settings/RenderSettings.cs b/source/RevitLookup.Abstractions/Models/Settings/RenderSettings.cs new file mode 100644 index 000000000..6e6103714 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/Settings/RenderSettings.cs @@ -0,0 +1,107 @@ +using System.Text.Json.Serialization; +using System.Windows.Media; + +namespace RevitLookup.Abstractions.Models.Settings; + +[Serializable] +public sealed class RenderSettings +{ + [JsonPropertyName("BoundingBoxSettings")] public required BoundingBoxVisualizationSettings BoundingBoxSettings { get; set; } + [JsonPropertyName("FaceSettings")] public required FaceVisualizationSettings FaceSettings { get; set; } + [JsonPropertyName("MeshSettings")] public required MeshVisualizationSettings MeshSettings { get; set; } + [JsonPropertyName("PolylineSettings")] public required PolylineVisualizationSettings PolylineSettings { get; set; } + [JsonPropertyName("SolidSettings")] public required SolidVisualizationSettings SolidSettings { get; set; } + [JsonPropertyName("XyzSettings")] public required XyzVisualizationSettings XyzSettings { get; set; } +} + +[Serializable] +public class BoundingBoxVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + + [JsonPropertyName("SurfaceColor")] public Color SurfaceColor { get; set; } + [JsonPropertyName("EdgeColor")] public Color EdgeColor { get; set; } + [JsonPropertyName("AxisColor")] public Color AxisColor { get; set; } + + [JsonPropertyName("ShowSurface")] public bool ShowSurface { get; set; } + [JsonPropertyName("ShowEdge")] public bool ShowEdge { get; set; } + [JsonPropertyName("ShowAxis")] public bool ShowAxis { get; set; } +} + +[Serializable] +public class FaceVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + [JsonPropertyName("Extrusion")] public double Extrusion { get; set; } + [JsonPropertyName("MinExtrusion")] public double MinExtrusion { get; set; } + + [JsonPropertyName("SurfaceColor")] public Color SurfaceColor { get; set; } + [JsonPropertyName("MeshColor")] public Color MeshColor { get; set; } + [JsonPropertyName("NormalVectorColor")] public Color NormalVectorColor { get; set; } + + [JsonPropertyName("ShowSurface")] public bool ShowSurface { get; set; } + [JsonPropertyName("ShowMeshGrid")] public bool ShowMeshGrid { get; set; } + [JsonPropertyName("ShowNormalVector")] public bool ShowNormalVector { get; set; } +} + +[Serializable] +public class MeshVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + [JsonPropertyName("Extrusion")] public double Extrusion { get; set; } + [JsonPropertyName("MinExtrusion")] public double MinExtrusion { get; set; } + + [JsonPropertyName("SurfaceColor")] public Color SurfaceColor { get; set; } + [JsonPropertyName("MeshColor")] public Color MeshColor { get; set; } + [JsonPropertyName("NormalVectorColor")] public Color NormalVectorColor { get; set; } + + [JsonPropertyName("ShowSurface")] public bool ShowSurface { get; set; } + [JsonPropertyName("ShowMeshGrid")] public bool ShowMeshGrid { get; set; } + [JsonPropertyName("ShowNormalVector")] public bool ShowNormalVector { get; set; } +} + +[Serializable] +public class PolylineVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + [JsonPropertyName("Diameter")] public double Diameter { get; set; } + [JsonPropertyName("MinThickness")] public double MinThickness { get; set; } + + [JsonPropertyName("SurfaceColor")] public Color SurfaceColor { get; set; } + [JsonPropertyName("CurveColor")] public Color CurveColor { get; set; } + [JsonPropertyName("DirectionColor")] public Color DirectionColor { get; set; } + + [JsonPropertyName("ShowSurface")] public bool ShowSurface { get; set; } + [JsonPropertyName("ShowCurve")] public bool ShowCurve { get; set; } + [JsonPropertyName("ShowDirection")] public bool ShowDirection { get; set; } +} + +[Serializable] +public sealed class SolidVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + [JsonPropertyName("Scale")] public double Scale { get; set; } + + [JsonPropertyName("FaceColor")] public Color FaceColor { get; set; } + [JsonPropertyName("EdgeColor")] public Color EdgeColor { get; set; } + + [JsonPropertyName("ShowFace")] public bool ShowFace { get; set; } + [JsonPropertyName("ShowEdge")] public bool ShowEdge { get; set; } +} + +[Serializable] +public class XyzVisualizationSettings +{ + [JsonPropertyName("Transparency")] public double Transparency { get; set; } + [JsonPropertyName("AxisLength")] public double AxisLength { get; set; } + [JsonPropertyName("MinAxisLength")] public double MinAxisLength { get; set; } + + [JsonPropertyName("XColor")] public Color XColor { get; set; } + [JsonPropertyName("YColor")] public Color YColor { get; set; } + [JsonPropertyName("ZColor")] public Color ZColor { get; set; } + + [JsonPropertyName("ShowPlane")] public bool ShowPlane { get; set; } + [JsonPropertyName("ShowXAxis")] public bool ShowXAxis { get; set; } + [JsonPropertyName("ShowYAxis")] public bool ShowYAxis { get; set; } + [JsonPropertyName("ShowZAxis")] public bool ShowZAxis { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup/Models/ModuleInfo.cs b/source/RevitLookup.Abstractions/Models/Tools/ModuleInfo.cs similarity index 96% rename from source/RevitLookup/Models/ModuleInfo.cs rename to source/RevitLookup.Abstractions/Models/Tools/ModuleInfo.cs index 2abae7f69..8c4103abb 100644 --- a/source/RevitLookup/Models/ModuleInfo.cs +++ b/source/RevitLookup.Abstractions/Models/Tools/ModuleInfo.cs @@ -18,7 +18,7 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Models; +namespace RevitLookup.Abstractions.Models.Tools; public sealed class ModuleInfo { diff --git a/source/RevitLookup.Abstractions/Models/Tools/UnitInfo.cs b/source/RevitLookup.Abstractions/Models/Tools/UnitInfo.cs new file mode 100644 index 000000000..bc2705969 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/Tools/UnitInfo.cs @@ -0,0 +1,29 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +namespace RevitLookup.Abstractions.Models.Tools; + +public sealed class UnitInfo +{ + public required string Unit { get; init; } + public required string Label { get; init; } + public required object Value { get; init; } + public string? Class { get; init; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardGroup.cs b/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardGroup.cs new file mode 100644 index 000000000..36f2e66e8 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardGroup.cs @@ -0,0 +1,7 @@ +namespace RevitLookup.Abstractions.Models.UserInterface; + +public sealed class NavigationCardGroup +{ + public required string GroupName { get; set; } + public required List Items { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardItem.cs b/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardItem.cs new file mode 100644 index 000000000..4aadf9250 --- /dev/null +++ b/source/RevitLookup.Abstractions/Models/UserInterface/NavigationCardItem.cs @@ -0,0 +1,13 @@ +using System.Windows.Input; +using Wpf.Ui.Controls; + +namespace RevitLookup.Abstractions.Models.UserInterface; + +public sealed class NavigationCardItem +{ + public required string Title { get; set; } + public string? Description { get; set; } + public required SymbolRegular Icon { get; set; } + public required ICommand Command { get; set; } + public object? CommandParameter { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedMember.cs b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedMember.cs new file mode 100644 index 000000000..60245a613 --- /dev/null +++ b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedMember.cs @@ -0,0 +1,16 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using LookupEngine.Abstractions.Enums; + +namespace RevitLookup.Abstractions.ObservableModels.Decomposition; + +public sealed class ObservableDecomposedMember : ObservableObject +{ + public required int Depth { get; set; } + public required string Name { get; set; } + public required string DeclaringTypeName { get; set; } + public required string DeclaringTypeFullName { get; set; } + public double ComputationTime { get; set; } + public long AllocatedBytes { get; set; } + public MemberAttributes MemberAttributes { get; set; } + public required ObservableDecomposedValue Value { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObject.cs b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObject.cs new file mode 100644 index 000000000..cc5c68259 --- /dev/null +++ b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObject.cs @@ -0,0 +1,22 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Abstractions.ObservableModels.Decomposition; + +public sealed partial class ObservableDecomposedObject : ObservableObject +{ + [ObservableProperty] private List _members = []; + [ObservableProperty] private List _filteredMembers = []; + + public required object? RawValue { get; init; } + public required string Name { get; set; } + public required string TypeName { get; set; } + public required string TypeFullName { get; set; } + public string? Description { get; set; } + public Descriptor? Descriptor { get; init; } + + partial void OnMembersChanged(List value) + { + FilteredMembers = value; + } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObjectsGroup.cs b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObjectsGroup.cs new file mode 100644 index 000000000..345ecda9f --- /dev/null +++ b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedObjectsGroup.cs @@ -0,0 +1,10 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace RevitLookup.Abstractions.ObservableModels.Decomposition; + +public sealed class ObservableDecomposedObjectsGroup : ObservableObject +{ + public required string GroupName { get; set; } + public required ObservableCollection GroupItems { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedValue.cs b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedValue.cs new file mode 100644 index 000000000..37018719f --- /dev/null +++ b/source/RevitLookup.Abstractions/ObservableModels/Decomposition/ObservableDecomposedValue.cs @@ -0,0 +1,14 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Abstractions.ObservableModels.Decomposition; + +public sealed class ObservableDecomposedValue : ObservableObject +{ + public required object? RawValue { get; init; } + public required string Name { get; set; } + public required string TypeName { get; set; } + public required string TypeFullName { get; set; } + public string? Description { get; set; } + public Descriptor? Descriptor { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ObservableModels/Entries/ObservableIniEntry.cs b/source/RevitLookup.Abstractions/ObservableModels/Entries/ObservableIniEntry.cs new file mode 100644 index 000000000..c05bd86ce --- /dev/null +++ b/source/RevitLookup.Abstractions/ObservableModels/Entries/ObservableIniEntry.cs @@ -0,0 +1,66 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.ComponentModel.DataAnnotations; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace RevitLookup.Abstractions.ObservableModels.Entries; + +public sealed partial class ObservableIniEntry : ObservableValidator +{ + [ObservableProperty] [Required] [NotifyDataErrorInfo] private string _category = string.Empty; + [ObservableProperty] [Required] [NotifyDataErrorInfo] private string _property = string.Empty; + [ObservableProperty] private string _value = string.Empty; + [ObservableProperty] private string? _defaultValue; + [ObservableProperty] private bool _isActive; + [ObservableProperty] private bool _isModified; + + public bool UserDefined { get; set; } + + public void Validate() + { + ValidateAllProperties(); + } + + partial void OnIsActiveChanged(bool value) + { + UserDefined = true; + } + + partial void OnValueChanged(string value) + { + IsModified = DefaultValue is not null && value != DefaultValue; + } + + partial void OnDefaultValueChanged(string? value) + { + IsModified = value != Value; + } + + public ObservableIniEntry Clone() + { + return new ObservableIniEntry + { + Category = Category, + Property = Property, + Value = Value + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Options/AssemblyOptions.cs b/source/RevitLookup.Abstractions/Options/AssemblyOptions.cs new file mode 100644 index 000000000..2f0deb717 --- /dev/null +++ b/source/RevitLookup.Abstractions/Options/AssemblyOptions.cs @@ -0,0 +1,8 @@ +namespace RevitLookup.Abstractions.Options; + +public sealed class AssemblyOptions +{ + public required string Framework { get; set; } + public required Version Version { get; set; } + public required bool HasAdminAccess { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Options/FoldersOptions.cs b/source/RevitLookup.Abstractions/Options/FoldersOptions.cs new file mode 100644 index 000000000..2fc5739a9 --- /dev/null +++ b/source/RevitLookup.Abstractions/Options/FoldersOptions.cs @@ -0,0 +1,10 @@ +namespace RevitLookup.Abstractions.Options; + +public sealed class FoldersOptions +{ + public required string RootFolder { get; set; } + public required string ConfigFolder { get; set; } + public required string DownloadsFolder { get; set; } + public required string GeneralSettingsPath { get; set; } + public required string RenderSettingsPath { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/RevitLookup.Abstractions.csproj b/source/RevitLookup.Abstractions/RevitLookup.Abstractions.csproj new file mode 100644 index 000000000..a9d6178bf --- /dev/null +++ b/source/RevitLookup.Abstractions/RevitLookup.Abstractions.csproj @@ -0,0 +1,27 @@ + + + + net48;net8.0-windows + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Appearance/IThemeWatcherService.cs b/source/RevitLookup.Abstractions/Services/Appearance/IThemeWatcherService.cs new file mode 100644 index 000000000..fb33870ef --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Appearance/IThemeWatcherService.cs @@ -0,0 +1,11 @@ +using System.Windows; + +namespace RevitLookup.Abstractions.Services.Appearance; + +public interface IThemeWatcherService +{ + void Initialize(); + void Watch(); + void Watch(FrameworkElement frameworkElement); + void Unwatch(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Application/IRevitLookupUiService.cs b/source/RevitLookup.Abstractions/Services/Application/IRevitLookupUiService.cs new file mode 100644 index 000000000..d64830bdb --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Application/IRevitLookupUiService.cs @@ -0,0 +1,32 @@ +using System.Collections; +using System.Windows; +using System.Windows.Controls; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Abstractions.Services.Application; + +public interface IRevitLookupUiService : ILookupServiceDependsStage, ILookupServiceRunStage +{ + ILookupServiceDependsStage Decompose(KnownDecompositionObject decompositionObject); + ILookupServiceDependsStage Decompose(object? obj); + ILookupServiceDependsStage Decompose(IEnumerable objects); + ILookupServiceDependsStage Decompose(ObservableDecomposedObject decomposedObject); + ILookupServiceDependsStage Decompose(List decomposedObjects); +} + +public interface ILookupServiceDependsStage : ILookupServiceShowStage +{ + ILookupServiceShowStage DependsOn(Window parent); +} + +public interface ILookupServiceShowStage +{ + ILookupServiceRunStage Show() where T : Page; + // ILookupServiceRunStage ShowDialog() where T : Page; +} + +public interface ILookupServiceRunStage +{ + void RunService(Action handler) where T : class; +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Decomposition/IDecompositionService.cs b/source/RevitLookup.Abstractions/Services/Decomposition/IDecompositionService.cs new file mode 100644 index 000000000..efddf22bf --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Decomposition/IDecompositionService.cs @@ -0,0 +1,11 @@ +using System.Collections; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Abstractions.Services.Decomposition; + +public interface IDecompositionService +{ + Task DecomposeAsync(object obj); + Task> DecomposeAsync(IEnumerable objects); + Task> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Decomposition/IVisualDecompositionService.cs b/source/RevitLookup.Abstractions/Services/Decomposition/IVisualDecompositionService.cs new file mode 100644 index 000000000..d1819c4cf --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Decomposition/IVisualDecompositionService.cs @@ -0,0 +1,14 @@ +using System.Collections; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Abstractions.Services.Decomposition; + +public interface IVisualDecompositionService +{ + Task VisualizeDecompositionAsync(KnownDecompositionObject decompositionObject); + Task VisualizeDecompositionAsync(object? obj); + Task VisualizeDecompositionAsync(IEnumerable objects); + Task VisualizeDecompositionAsync(ObservableDecomposedObject decomposedObject); + Task VisualizeDecompositionAsync(List decomposedObjects); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Presentation/INotificationService.cs b/source/RevitLookup.Abstractions/Services/Presentation/INotificationService.cs new file mode 100644 index 000000000..0d1b03161 --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Presentation/INotificationService.cs @@ -0,0 +1,9 @@ +namespace RevitLookup.Abstractions.Services.Presentation; + +public interface INotificationService +{ + void ShowSuccess(string title, string message); + void ShowWarning(string title, string message); + void ShowError(string title, string message); + void ShowError(string title, Exception exception); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Presentation/IWindowIntercomService.cs b/source/RevitLookup.Abstractions/Services/Presentation/IWindowIntercomService.cs new file mode 100644 index 000000000..4cb5dd1da --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Presentation/IWindowIntercomService.cs @@ -0,0 +1,14 @@ +using System.Windows; +using System.Windows.Threading; + +namespace RevitLookup.Abstractions.Services.Presentation; + +public interface IWindowIntercomService +{ + Dispatcher Dispatcher { get; } + List OpenedWindows { get; } + + Window GetHost(); + void SetHost(Window host); + void SetSharedHost(Window host); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Settings/ISettingsService.cs b/source/RevitLookup.Abstractions/Services/Settings/ISettingsService.cs new file mode 100644 index 000000000..54d24b693 --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Settings/ISettingsService.cs @@ -0,0 +1,13 @@ +using RevitLookup.Abstractions.Models.Settings; + +namespace RevitLookup.Abstractions.Services.Settings; + +public interface ISettingsService +{ + public GeneralSettings GeneralSettings { get; } + public RenderSettings RenderSettings { get; } + void SaveSettings(); + void LoadSettings(); + void ResetGeneralSettings(); + void ResetRenderSettings(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/Services/Settings/ISoftwareUpdateService.cs b/source/RevitLookup.Abstractions/Services/Settings/ISoftwareUpdateService.cs new file mode 100644 index 000000000..f8336265d --- /dev/null +++ b/source/RevitLookup.Abstractions/Services/Settings/ISoftwareUpdateService.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +namespace RevitLookup.Abstractions.Services.Settings; + +public interface ISoftwareUpdateService +{ + public string? NewVersion { get; } + public string? ReleaseNotesUrl { get; } + public string? LocalFilePath { get; } + public DateTime? LatestCheckDate { get; } + + Task CheckUpdatesAsync(); + Task DownloadUpdate(); +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Enums/SoftwareUpdateState.cs b/source/RevitLookup.Abstractions/States/SoftwareUpdateState.cs similarity index 91% rename from source/RevitLookup/Services/Enums/SoftwareUpdateState.cs rename to source/RevitLookup.Abstractions/States/SoftwareUpdateState.cs index 305b455c6..dac9c0f9c 100644 --- a/source/RevitLookup/Services/Enums/SoftwareUpdateState.cs +++ b/source/RevitLookup.Abstractions/States/SoftwareUpdateState.cs @@ -18,13 +18,12 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Services.Enums; +namespace RevitLookup.Abstractions.States; public enum SoftwareUpdateState { UpToDate, - ErrorDownloading, - ErrorChecking, ReadyToDownload, - ReadyToInstall + ReadyToInstall, + Error } \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IAboutViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IAboutViewModel.cs new file mode 100644 index 000000000..ee6ef7964 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IAboutViewModel.cs @@ -0,0 +1,19 @@ +using CommunityToolkit.Mvvm.Input; +using RevitLookup.Abstractions.States; + +namespace RevitLookup.Abstractions.ViewModels.AboutProgram; + +public interface IAboutViewModel +{ + SoftwareUpdateState State { get; set; } + Version CurrentVersion { get; set; } + string NewVersion { get; set; } + string ErrorMessage { get; set; } + string ReleaseNotesUrl { get; set; } + string LatestCheckDate { get; set; } + string Runtime { get; set; } + + IAsyncRelayCommand CheckUpdatesCommand { get; } + IAsyncRelayCommand DownloadUpdateCommand { get; } + IAsyncRelayCommand ShowSoftwareDialogCommand { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IOpenSourceViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IOpenSourceViewModel.cs new file mode 100644 index 000000000..1122e1f24 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/AboutProgram/IOpenSourceViewModel.cs @@ -0,0 +1,8 @@ +using RevitLookup.Abstractions.Models.AboutProgram; + +namespace RevitLookup.Abstractions.ViewModels.AboutProgram; + +public interface IOpenSourceViewModel +{ + List Software { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Dashboard/IDashboardViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Dashboard/IDashboardViewModel.cs new file mode 100644 index 000000000..675aa08e6 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Dashboard/IDashboardViewModel.cs @@ -0,0 +1,31 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using CommunityToolkit.Mvvm.Input; +using RevitLookup.Abstractions.Models.UserInterface; + +namespace RevitLookup.Abstractions.ViewModels.Dashboard; + +public interface IDashboardViewModel +{ + List NavigationGroups { get; } + IAsyncRelayCommand NavigatePageCommand { get; } + IAsyncRelayCommand OpenDialogCommand { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Decomposition/IDecompositionSummaryViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Decomposition/IDecompositionSummaryViewModel.cs new file mode 100644 index 000000000..e7febfb9e --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Decomposition/IDecompositionSummaryViewModel.cs @@ -0,0 +1,10 @@ +using System.Collections.ObjectModel; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Abstractions.ViewModels.Decomposition; + +public interface IDecompositionSummaryViewModel : ISummaryViewModel +{ + ObservableCollection FilteredDecomposedObjects { get; } + void RemoveItem(object target); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Decomposition/IEventsSummaryViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Decomposition/IEventsSummaryViewModel.cs new file mode 100644 index 000000000..7a3308eb8 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Decomposition/IEventsSummaryViewModel.cs @@ -0,0 +1,10 @@ +using System.Collections.ObjectModel; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.Abstractions.ViewModels.Decomposition; + +public interface IEventsSummaryViewModel : ISummaryViewModel, INavigationAware +{ + ObservableCollection FilteredDecomposedObjects { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Decomposition/ISummaryViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Decomposition/ISummaryViewModel.cs new file mode 100644 index 000000000..fe740ff9a --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Decomposition/ISummaryViewModel.cs @@ -0,0 +1,20 @@ +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Abstractions.ViewModels.Decomposition; + +public interface ISummaryViewModel +{ + string SearchText { get; set; } + + //Objects + ObservableDecomposedObject? SelectedDecomposedObject { get; set; } + List DecomposedObjects { get; set; } + + //Commands + Task RefreshMembersAsync(); + + //Navigation + void Navigate(object? value); + void Navigate(ObservableDecomposedObject value); + void Navigate(List values); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Settings/ISettingsViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Settings/ISettingsViewModel.cs new file mode 100644 index 000000000..a17ef330d --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Settings/ISettingsViewModel.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using CommunityToolkit.Mvvm.Input; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace RevitLookup.Abstractions.ViewModels.Settings; + +public interface ISettingsViewModel +{ + ApplicationTheme Theme { get; set; } + List Themes { get; } + WindowBackdropType Background { get; set; } + List BackgroundEffects { get; } + bool UseTransition { get; set; } + bool UseHardwareRendering { get; set; } + bool UseSizeRestoring { get; set; } + bool UseModifyTab { get; set; } + + IAsyncRelayCommand ResetSettingsCommand { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Tools/IModulesViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Tools/IModulesViewModel.cs new file mode 100644 index 000000000..c016c42c1 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Tools/IModulesViewModel.cs @@ -0,0 +1,10 @@ +using RevitLookup.Abstractions.Models.Tools; + +namespace RevitLookup.Abstractions.ViewModels.Tools; + +public interface IModulesViewModel +{ + string SearchText { get; set; } + List FilteredModules { get; set; } + List Modules { get; set; } +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Tools/IRevitSettingsViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Tools/IRevitSettingsViewModel.cs new file mode 100644 index 000000000..bb2cacbe9 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Tools/IRevitSettingsViewModel.cs @@ -0,0 +1,33 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.Input; +using RevitLookup.Abstractions.ObservableModels.Entries; + +namespace RevitLookup.Abstractions.ViewModels.Tools; + +public interface IRevitSettingsViewModel +{ + //Filter + bool Filtered { get; set; } + string CategoryFilter { get; set; } + string PropertyFilter { get; set; } + string ValueFilter { get; set; } + bool ShowUserSettingsFilter { get; set; } + + //Items + ObservableIniEntry? SelectedEntry { get; set; } + List Entries { get; set; } + ObservableCollection FilteredEntries { get; set; } + + //Commands + IRelayCommand ShowHelpCommand { get; } + IRelayCommand OpenSettingsCommand { get; } + IRelayCommand ClearFiltersCommand { get; } + IAsyncRelayCommand CreateEntryCommand { get; } + IRelayCommand ActivateEntryCommand { get; } + IRelayCommand DeleteEntryCommand { get; } + IRelayCommand RestoreDefaultCommand { get; } + + Task>? InitializationTask { get; } + Task InitializeAsync(); + Task UpdateEntryAsync(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Tools/ISearchElementsViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Tools/ISearchElementsViewModel.cs new file mode 100644 index 000000000..45119a59a --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Tools/ISearchElementsViewModel.cs @@ -0,0 +1,7 @@ +namespace RevitLookup.Abstractions.ViewModels.Tools; + +public interface ISearchElementsViewModel +{ + string SearchText { get; set; } + Task SearchElementsAsync(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Tools/IUnitsViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Tools/IUnitsViewModel.cs new file mode 100644 index 000000000..014ab79b1 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Tools/IUnitsViewModel.cs @@ -0,0 +1,14 @@ +using RevitLookup.Abstractions.Models.Tools; + +namespace RevitLookup.Abstractions.ViewModels.Tools; + +public interface IUnitsViewModel +{ + List Units { get; set; } + List FilteredUnits { get; set; } + string SearchText { get; set; } + void InitializeParameters(); + void InitializeCategories(); + void InitializeForgeSchema(); + Task DecomposeAsync(UnitInfo unitInfo); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/IBoundingBoxVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/IBoundingBoxVisualizationViewModel.cs new file mode 100644 index 000000000..6826b3e02 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/IBoundingBoxVisualizationViewModel.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface IBoundingBoxVisualizationViewModel +{ + double Transparency { get; set; } + + Color SurfaceColor { get; set; } + Color EdgeColor { get; set; } + Color AxisColor { get; set; } + + bool ShowSurface { get; set; } + bool ShowEdge { get; set; } + bool ShowAxis { get; set; } + + void RegisterServer(object boundingBoxXyz); + void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/IFaceVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/IFaceVisualizationViewModel.cs new file mode 100644 index 000000000..dd1a4fd8f --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/IFaceVisualizationViewModel.cs @@ -0,0 +1,42 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface IFaceVisualizationViewModel +{ + public double MinExtrusion { get; } + + double Extrusion { get; set; } + double Transparency { get; set; } + + Color SurfaceColor { get; set; } + Color MeshColor { get; set; } + Color NormalVectorColor { get; set; } + + bool ShowSurface { get; set; } + bool ShowMeshGrid { get; set; } + bool ShowNormalVector { get; set; } + + public void RegisterServer(object face); + public void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/IMeshVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/IMeshVisualizationViewModel.cs new file mode 100644 index 000000000..8955a9b5f --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/IMeshVisualizationViewModel.cs @@ -0,0 +1,42 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface IMeshVisualizationViewModel +{ + public double MinExtrusion { get; } + + double Extrusion { get; set; } + double Transparency { get; set; } + + Color SurfaceColor { get; set; } + Color MeshColor { get; set; } + Color NormalVectorColor { get; set; } + + bool ShowSurface { get; set; } + bool ShowMeshGrid { get; set; } + bool ShowNormalVector { get; set; } + + public void RegisterServer(object mesh); + public void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/IPolylineVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/IPolylineVisualizationViewModel.cs new file mode 100644 index 000000000..62c2c5884 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/IPolylineVisualizationViewModel.cs @@ -0,0 +1,42 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface IPolylineVisualizationViewModel +{ + double MinThickness { get; } + + double Diameter { get; set; } + double Transparency { get; set; } + + Color SurfaceColor { get; set; } + Color CurveColor { get; set; } + Color DirectionColor { get; set; } + + bool ShowSurface { get; set; } + bool ShowCurve { get; set; } + bool ShowDirection { get; set; } + + public void RegisterServer(object curveOrEdge); + public void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/ISolidVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/ISolidVisualizationViewModel.cs new file mode 100644 index 000000000..427d140e5 --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/ISolidVisualizationViewModel.cs @@ -0,0 +1,38 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface ISolidVisualizationViewModel +{ + double Scale { get; set; } + double Transparency { get; set; } + + Color FaceColor { get; set; } + Color EdgeColor { get; set; } + + bool ShowFace { get; set; } + bool ShowEdge { get; set; } + + public void RegisterServer(object solid); + public void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Abstractions/ViewModels/Visualization/IXyzVisualizationViewModel.cs b/source/RevitLookup.Abstractions/ViewModels/Visualization/IXyzVisualizationViewModel.cs new file mode 100644 index 000000000..55d9a0a8e --- /dev/null +++ b/source/RevitLookup.Abstractions/ViewModels/Visualization/IXyzVisualizationViewModel.cs @@ -0,0 +1,43 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Media; + +namespace RevitLookup.Abstractions.ViewModels.Visualization; + +public interface IXyzVisualizationViewModel +{ + public double MinAxisLength { get; } + + double AxisLength { get; set; } + double Transparency { get; set; } + + Color XColor { get; set; } + Color YColor { get; set; } + Color ZColor { get; set; } + + bool ShowPlane { get; set; } + bool ShowXAxis { get; set; } + bool ShowYAxis { get; set; } + bool ShowZAxis { get; set; } + + public void RegisterServer(object xyz); + public void UnregisterServer(); +} \ No newline at end of file diff --git a/source/RevitLookup.Common/RevitLookup.Common.csproj b/source/RevitLookup.Common/RevitLookup.Common.csproj new file mode 100644 index 000000000..44b5e7bfa --- /dev/null +++ b/source/RevitLookup.Common/RevitLookup.Common.csproj @@ -0,0 +1,12 @@ + + + + true + net48;net8.0-windows + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.Common/Tools/ProcessTasks.cs b/source/RevitLookup.Common/Tools/ProcessTasks.cs new file mode 100644 index 000000000..bfbe343de --- /dev/null +++ b/source/RevitLookup.Common/Tools/ProcessTasks.cs @@ -0,0 +1,70 @@ +using System.Diagnostics; +using System.Text; + +namespace RevitLookup.Common.Tools; + +public static class ProcessTasks +{ + public static Process? StartProcess(string toolPath, string arguments = "", Action? logger = null) + { + var startInfo = new ProcessStartInfo + { + FileName = toolPath, + Arguments = arguments, + CreateNoWindow = true, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + StandardOutputEncoding = Encoding.UTF8, + StandardErrorEncoding = Encoding.UTF8 + }; + + var process = Process.Start(startInfo); + if (process == null) return null; + + RedirectProcessOutput(process, logger); + return process; + } + + public static Process? StartShell(string toolPath, string arguments = "") + { + var startInfo = new ProcessStartInfo + { + FileName = toolPath, + Arguments = arguments, + CreateNoWindow = true, + UseShellExecute = true + }; + + return Process.Start(startInfo); + } + + private static void RedirectProcessOutput(Process process, Action? logger) + { + logger ??= DefaultLogger; + process.OutputDataReceived += (_, args) => + { + if (string.IsNullOrEmpty(args.Data)) return; + logger.Invoke(OutputType.Standard, args.Data); + }; + process.ErrorDataReceived += (_, args) => + { + if (string.IsNullOrEmpty(args.Data)) return; + logger.Invoke(OutputType.Error, args.Data); + }; + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + } + + private static void DefaultLogger(OutputType type, string output) + { + Console.WriteLine(output); + } +} + +public enum OutputType +{ + Standard, + Error +} \ No newline at end of file diff --git a/source/RevitLookup.Common/Utils/AccessUtils.cs b/source/RevitLookup.Common/Utils/AccessUtils.cs new file mode 100644 index 000000000..3d13eaf70 --- /dev/null +++ b/source/RevitLookup.Common/Utils/AccessUtils.cs @@ -0,0 +1,47 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.IO; +using System.Security.AccessControl; +using System.Security.Principal; + +namespace RevitLookup.Common.Utils; + +public static class AccessUtils +{ + public static bool CheckWriteAccess(string path) + { + var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + var accessControl = new DirectoryInfo(path).GetAccessControl(); + var accessRules = accessControl.GetAccessRules(true, true, typeof(NTAccount)); + var writeAccess = false; + foreach (FileSystemAccessRule rule in accessRules) + { + if (principal.IsInRole(rule.IdentityReference.Value) && (rule.FileSystemRights & FileSystemRights.WriteData) == FileSystemRights.WriteData) + { + writeAccess = true; + break; + } + } + + return writeAccess; + } +} \ No newline at end of file diff --git a/source/RevitLookup.Common/Utils/ColorFormatUtils.cs b/source/RevitLookup.Common/Utils/ColorFormatUtils.cs new file mode 100644 index 000000000..2deeb814a --- /dev/null +++ b/source/RevitLookup.Common/Utils/ColorFormatUtils.cs @@ -0,0 +1,270 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Color = System.Drawing.Color; + +namespace RevitLookup.Common.Utils; + +/// +/// Helper class to easier work with color formats +/// +/// +/// Implementation: https://github.com/microsoft/PowerToys/blob/main/src/common/ManagedCommon/ColorFormatHelper.cs +/// +public static class ColorFormatUtils +{ + /// + /// Return a drawing color of a given + /// + public static Color GetDrawingColor(this System.Windows.Media.Color color) + { + return Color.FromArgb(1, color.R, color.G, color.B); + } + + /// + /// Convert a given to a CMYK color (cyan, magenta, yellow, black key) + /// + /// The to convert + /// The cyan[0..1], magenta[0..1], yellow[0..1] and black key[0..1] of the converted color + public static (double Cyan, double Magenta, double Yellow, double BlackKey) ConvertToCmykColor(Color color) + { + // special case for black (avoid division by zero) + if (color is {R: 0, G: 0, B: 0}) + { + return (0d, 0d, 0d, 1d); + } + + var red = color.R / 255d; + var green = color.G / 255d; + var blue = color.B / 255d; + + var blackKey = 1d - Math.Max(Math.Max(red, green), blue); + + // special case for black (avoid division by zero) + if (1d - blackKey == 0d) + { + return (0d, 0d, 0d, 1d); + } + + var cyan = (1d - red - blackKey) / (1d - blackKey); + var magenta = (1d - green - blackKey) / (1d - blackKey); + var yellow = (1d - blue - blackKey) / (1d - blackKey); + + return (cyan, magenta, yellow, blackKey); + } + + /// + /// Convert a given to a HSB color (hue, saturation, brightness) + /// + /// The to convert + /// The hue [0°..360°], saturation [0..1] and brightness [0..1] of the converted color + public static (double Hue, double Saturation, double Brightness) ConvertToHsbColor(Color color) + { + // HSB and HSV represents the same color space + return ConvertToHsvColor(color); + } + + /// + /// Convert a given to a HSV color (hue, saturation, value) + /// + /// The to convert + /// The hue [0°..360°], saturation [0..1] and value [0..1] of the converted color + public static (double Hue, double Saturation, double Value) ConvertToHsvColor(Color color) + { + var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d; + var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d; + + return (color.GetHue(), max == 0d ? 0d : (max - min) / max, max); + } + + /// + /// Convert a given to a HSI color (hue, saturation, intensity) + /// + /// The to convert + /// The hue [0°..360°], saturation [0..1] and intensity [0..1] of the converted color + public static (double Hue, double Saturation, double Intensity) ConvertToHsiColor(Color color) + { + // special case for black + if (color.R == 0 && color.G == 0 && color.B == 0) + { + return (0d, 0d, 0d); + } + + var red = color.R / 255d; + var green = color.G / 255d; + var blue = color.B / 255d; + + var intensity = (red + green + blue) / 3d; + + var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d; + + return (color.GetHue(), 1d - (min / intensity), intensity); + } + + /// + /// Convert a given to a HSL color (hue, saturation, lightness) + /// + /// The to convert + /// The hue [0°..360°], saturation [0..1] and lightness [0..1] values of the converted color + public static (double Hue, double Saturation, double Lightness) ConvertToHslColor(Color color) + { + var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d; + var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d; + + var lightness = (max + min) / 2d; + + if (lightness == 0d || Math.Abs(min - max) < 1e-9) + { + return (color.GetHue(), 0d, lightness); + } + + if (lightness is > 0d and <= 0.5d) + { + return (color.GetHue(), (max - min) / (max + min), lightness); + } + + return (color.GetHue(), (max - min) / (2d - (max + min)), lightness); + } + + /// + /// Convert a given to a HWB color (hue, whiteness, blackness) + /// + /// The to convert + /// The hue [0°..360°], whiteness [0..1] and blackness [0..1] of the converted color + public static (double Hue, double Whiteness, double Blackness) ConvertToHwbColor(Color color) + { + var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d; + var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d; + + return (color.GetHue(), min, 1 - max); + } + + /// + /// Convert a given to a CIE LAB color (LAB) + /// + /// The to convert + /// The lightness [0..100] and two chromaticities [-128..127] + public static (double Lightness, double ChromaticityA, double ChromaticityB) ConvertToCielabColor(Color color) + { + var xyz = ConvertToCiexyzColor(color); + var lab = GetCielabColorFromCieXyz(xyz.X, xyz.Y, xyz.Z); + + return lab; + } + + /// + /// Convert a given to a CIE XYZ color (XYZ) + /// The constants of the formula matches this Wikipedia page, but at a higher precision: + /// https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation_(sRGB_to_CIE_XYZ) + /// This page provides a method to calculate the constants: + /// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + /// + /// The to convert + /// The X [0..1], Y [0..1] and Z [0..1] + public static (double X, double Y, double Z) ConvertToCiexyzColor(Color color) + { + var r = color.R / 255d; + var g = color.G / 255d; + var b = color.B / 255d; + + // inverse companding, gamma correction must be undone + var rLinear = (r > 0.04045) ? Math.Pow((r + 0.055) / 1.055, 2.4) : (r / 12.92); + var gLinear = (g > 0.04045) ? Math.Pow((g + 0.055) / 1.055, 2.4) : (g / 12.92); + var bLinear = (b > 0.04045) ? Math.Pow((b + 0.055) / 1.055, 2.4) : (b / 12.92); + + return ( + (rLinear * 0.41239079926595948) + (gLinear * 0.35758433938387796) + (bLinear * 0.18048078840183429), + (rLinear * 0.21263900587151036) + (gLinear * 0.71516867876775593) + (bLinear * 0.07219231536073372), + (rLinear * 0.01933081871559185) + (gLinear * 0.11919477979462599) + (bLinear * 0.95053215224966058) + ); + } + + /// + /// Convert a CIE XYZ color to a CIE LAB color (LAB) adapted to sRGB D65 white point + /// The constants of the formula used come from this wikipedia page: + /// https://en.wikipedia.org/wiki/CIELAB_color_space#Converting_between_CIELAB_and_CIEXYZ_coordinates + /// + /// The represents a mix of the three CIE RGB curves + /// The represents the luminance + /// The is quasi-equal to blue (of CIE RGB) + /// The lightness [0..100] and two chromaticities [-128..127] + private static (double Lightness, double ChromaticityA, double ChromaticityB) GetCielabColorFromCieXyz(double x, double y, double z) + { + // sRGB reference white (x=0.3127, y=0.3290, Y=1.0), actually CIE Standard Illuminant D65 truncated to 4 decimal places, + // then converted to XYZ using the formula: + // X = x * (Y / y) + // Y = Y + // Z = (1 - x - y) * (Y / y) + const double xN = 0.9504559270516717; + const double yN = 1.0; + const double zN = 1.0890577507598784; + + // Scale XYZ values relative to reference white + x /= xN; + y /= yN; + z /= zN; + + // XYZ to CIELab transformation + const double delta = 6d / 29; + var m = (1d / 3) * Math.Pow(delta, -2); + var t = Math.Pow(delta, 3); + + var fx = (x > t) ? Math.Pow(x, 1.0 / 3.0) : (x * m) + (16.0 / 116.0); + var fy = (y > t) ? Math.Pow(y, 1.0 / 3.0) : (y * m) + (16.0 / 116.0); + var fz = (z > t) ? Math.Pow(z, 1.0 / 3.0) : (z * m) + (16.0 / 116.0); + + var l = (116 * fy) - 16; + var a = 500 * (fx - fy); + var b = 200 * (fy - fz); + + return (l, a, b); + } + + /// + /// Convert a given to a natural color (hue, whiteness, blackness) + /// + /// The to convert + /// The hue, whiteness [0..1] and blackness [0..1] of the converted color + public static (string Hue, double Whiteness, double Blackness) ConvertToNaturalColor(Color color) + { + var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d; + var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d; + + return (GetNaturalColorFromHue(color.GetHue()), min, 1 - max); + } + + /// + /// Return the natural color for the given hue value + /// + /// The hue value to convert + /// A natural color + private static string GetNaturalColorFromHue(double hue) + { + return hue switch + { + < 60d => $"R{Math.Round(hue / 0.6d, 0)}", + < 120d => $"Y{Math.Round((hue - 60d) / 0.6d, 0)}", + < 180d => $"G{Math.Round((hue - 120d) / 0.6d, 0)}", + < 240d => $"C{Math.Round((hue - 180d) / 0.6d, 0)}", + < 300d => $"B{Math.Round((hue - 240d) / 0.6d, 0)}", + _ => $"M{Math.Round((hue - 300d) / 0.6d, 0)}" + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.Common/Utils/ColorRepresentationUtils.cs b/source/RevitLookup.Common/Utils/ColorRepresentationUtils.cs new file mode 100644 index 000000000..a65aed4af --- /dev/null +++ b/source/RevitLookup.Common/Utils/ColorRepresentationUtils.cs @@ -0,0 +1,777 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using Color = System.Drawing.Color; + +namespace RevitLookup.Common.Utils; + +/// +/// Helper class to easier work with color representation +/// +/// +/// Implementation: https://github.com/microsoft/PowerToys/blob/main/src/modules/colorPicker/ColorPickerUI/Helpers/ColorRepresentationHelper.cs +/// +public static class ColorRepresentationUtils +{ + private static readonly Dictionary KnownColors = new() + { + {"000000", "Black"}, + {"000080", "Navy blue"}, + {"0000FF", "Blue"}, + {"0018A8", "Blue (Pantone)"}, + {"002E63", "Cool Black"}, + {"003153", "Prussian blue"}, + {"003366", "Midnight Blue"}, + {"003399", "Powder blue"}, + {"003A6C", "Ateneo blue"}, + {"004225", "British racing green"}, + {"0047AB", "Cobalt"}, + {"0048BA", "Absolute zero"}, + {"00563F", "Castleton green"}, + {"006A4E", "Bottle green"}, + {"006B3C", "Cadmium green"}, + {"007BA7", "Cerulean"}, + {"007DFF", "Gradus Blue"}, + {"007FFF", "Azure"}, + {"008080", "Teal"}, + {"0088DC", "Blue cola"}, + {"0093AF", "Blue (Munsell)"}, + {"0095B6", "Bondi Blue"}, + {"00A86B", "Jade"}, + {"00B9FB", "Blue Bolt"}, + {"00BFFF", "Deep sky blue"}, + {"00C4B0", "Amazonite"}, + {"00CC99", "Caribbean green"}, + {"00CCCC", "Robin egg blue"}, + {"00FF00", "Green"}, + {"00FF7F", "Spring Green"}, + {"00FFFF", "Aqua"}, + {"013220", "Dark green"}, + {"01796F", "Pine Green"}, + {"03C03C", "Dark pastel green"}, + {"064E40", "Blue-green (color wheel)"}, + {"082567", "Sapphire"}, + {"08457E", "Dark cerulean"}, + {"08E8DE", "Bright turquoise"}, + {"0A1195", "Cadmium blue"}, + {"0BDA51", "Malachite"}, + {"0D98BA", "Blue-green"}, + {"116062", "Dark turquoise"}, + {"120A8F", "Ultramarine"}, + {"126180", "Blue sapphire"}, + {"141414", "Chinese black"}, + {"1560BD", "Denim"}, + {"177245", "Dark spring green"}, + {"1974D2", "Bright navy blue"}, + {"1A4780", "Black Sea"}, + {"1B1811", "Black chocolate"}, + {"1B4D3E", "Brunswick green"}, + {"1C6B72", "Moray"}, + {"1DACD6", "Bright cerulean"}, + {"1E90FF", "Dodger blue"}, + {"1F4037", "Red Sea"}, + {"1F75FE", "Blue (Crayola)"}, + {"21ABCD", "Ball blue"}, + {"232B2B", "Charleston green"}, + {"246BCE", "Celtic Blue"}, + {"24A0ED", "Button Blue"}, + {"253529", "Black leather jacket"}, + {"2A52BE", "Cerulean blue"}, + {"2A8FBD", "Christmas blue"}, + {"2E2D88", "Cosmic Cobalt"}, + {"2E5894", "B'dazzled blue"}, + {"2E8B57", "Sea Green"}, + {"2F4F4F", "Dark slate gray"}, + {"30D5C8", "Turquoise"}, + {"310062", "Dark Indigo"}, + {"318CE7", "Bleu de France"}, + {"333399", "Blue (pigment)"}, + {"3399FF", "Brilliant azure"}, + {"34B334", "American green"}, + {"34C924", "Vert-de-pomme"}, + {"36454F", "Charcoal"}, + {"365194", "Chinese blue"}, + {"391802", "American bronze"}, + {"3A75C4", "Klein Blue"}, + {"3B2F2F", "Black coffee"}, + {"3B3B6D", "American blue"}, + {"3B3C36", "Black olive"}, + {"3B444B", "Arsenic"}, + {"3B7A57", "Amazon"}, + {"3C1421", "Chocolate Kisses"}, + {"3C3024", "Cola"}, + {"3C8D0D", "Christmas green"}, + {"3CAA3C", "Toad in love"}, + {"3D0C02", "Black bean"}, + {"3D2B1F", "Bistre"}, + {"3F000F", "Chocolate Brown"}, + {"40826D", "Viridian"}, + {"4169E1", "Royal Blue"}, + {"423189", "Dark violet"}, + {"442D25", "Coffee"}, + {"45161C", "Fulvous"}, + {"464451", "Anthracite"}, + {"465945", "Gray-asparagus"}, + {"4682B4", "Steel blue"}, + {"480607", "Bulgarian rose"}, + {"4A2C2A", "Brown Coffee"}, + {"4AFF00", "Chlorophyll green"}, + {"4B0082", "Indigo"}, + {"4B3621", "Caf? noir"}, + {"4B5320", "Army green"}, + {"4C2F27", "Acajou"}, + {"4C5866", "Marengo"}, + {"4D1A7F", "Blue-violet (color wheel)"}, + {"4E1609", "Flea belly"}, + {"4F7942", "Fern green"}, + {"4F86F7", "Blueberry"}, + {"5072A7", "Blue yonder"}, + {"50C878", "Emerald"}, + {"54626F", "Black Coral"}, + {"551B8C", "American violet"}, + {"553592", "Blue-magenta violet"}, + {"556832", "Dark Olive"}, + {"560319", "Dark Scarlet"}, + {"568203", "Avocado"}, + {"56A0D3", "Carolina blue"}, + {"58111A", "Chocolate Cosmos"}, + {"592720", "Caput mortuum"}, + {"5D2B2C", "Christmas brown"}, + {"5D8AA8", "Air Force Navy(RAF)"}, + {"5DA130", "Grass"}, + {"5DADEC", "Blue Jeans"}, + {"5F1933", "Brown Chocolate"}, + {"630F0F", "Blood (Organ)"}, + {"63775B", "Axolotl"}, + {"6495ED", "Cornflower blue"}, + {"654321", "Dark brown"}, + {"660000", "Blood red"}, + {"660066", "Plum"}, + {"660099", "Purple"}, + {"6600FF", "Persian blue"}, + {"663398", "Christmas purple"}, + {"665D1E", "Antique bronze"}, + {"6699CC", "Blue-gray"}, + {"66B447", "Apple"}, + {"66FF00", "Bright green"}, + {"6B4423", "Brown-nose"}, + {"6B8E23", "Olive Drab"}, + {"6E7F80", "AuroMetalSaurus"}, + {"702963", "Byzantium"}, + {"703642", "Catawba"}, + {"704214", "Sepia"}, + {"708090", "Slate gray"}, + {"720B98", "Chinese purple"}, + {"72A0C1", "Air superiority blue"}, + {"734A12", "Raw umber"}, + {"735184", "Seroburomalinovyj"}, + {"7366BD", "Blue-violet (Crayola)"}, + {"737000", "Bronze Yellow"}, + {"755A57", "Russet"}, + {"77DD77", "Pastel green"}, + {"78866B", "Camouflage green"}, + {"79443B", "Bole"}, + {"79A0C1", "Bluish"}, + {"7B3F00", "Cinnamon"}, + {"7B917B", "Fainted frog"}, + {"7BA05B", "Asparagus"}, + {"7BB661", "Bud green"}, + {"7C0A02", "Barn red"}, + {"7CB9E8", "Aero"}, + {"7DF9FF", "Electric"}, + {"7F1734", "Claret"}, + {"7F3E98", "Cadmium violet"}, + {"7FC7FF", "Sky"}, + {"7FFF00", "Chartreuse"}, + {"7FFFD4", "Aquamarine"}, + {"800000", "Maroon"}, + {"800020", "Burgundy"}, + {"804040", "American brown"}, + {"808000", "Olive"}, + {"808080", "Gray"}, + {"81613C", "Coyote brown"}, + {"834D18", "Byron"}, + {"841B2D", "Antique ruby"}, + {"848482", "Battleship grey"}, + {"84DE02", "Alien Armpit"}, + {"856088", "Chinese violet"}, + {"87413F", "Brandy"}, + {"87A96B", "Asparagus"}, + {"884535", "Brick"}, + {"893F45", "Cordovan"}, + {"89CFF0", "Baby blue"}, + {"8A0303", "Blood"}, + {"8A2BE2", "Blue-violet"}, + {"8A3324", "Burnt umber"}, + {"8B00FF", "Violet"}, + {"8C92AC", "Cool grey"}, + {"8DB600", "Apple Green"}, + {"8F5973", "Blackberry"}, + {"8F9779", "Artichoke"}, + {"900020", "Burgundy"}, + {"904D30", "Terracotta"}, + {"911E42", "Cherry"}, + {"915C83", "Antique fuchsia"}, + {"918151", "Dark tan"}, + {"92000A", "Sangria"}, + {"954535", "Chestnut"}, + {"960018", "Carmine"}, + {"964B00", "Brown"}, + {"965A3E", "Coconut"}, + {"967117", "Bistre brown"}, + {"986960", "Dark chestnut"}, + {"987654", "Pale brown"}, + {"98777B", "Bazaar"}, + {"98817B", "Cinereous"}, + {"98FF98", "Mint Green"}, + {"990066", "Eggplant"}, + {"991199", "Violet-eggplant"}, + {"993366", "Mauve"}, + {"996666", "Copper rose"}, + {"9966CC", "Amethyst"}, + {"997A8D", "Mountbatten pink"}, + {"99958C", "Quartz"}, + {"9B2D30", "Wine red"}, + {"9C2542", "Big dip o’ruby"}, + {"9DB1CC", "Niagara"}, + {"9F2B68", "Amaranth deep purple"}, + {"9F8170", "Beaver"}, + {"9FA91F", "Citron"}, + {"A08040", "Chamois"}, + {"A17A74", "Burnished Brown"}, + {"A1CAF1", "Baby blue eyes"}, + {"A25F2A", "Camelopardalis"}, + {"A2A2D0", "Blue Bell"}, + {"A41313", "Blood (Animal)"}, + {"A4C639", "Android green"}, + {"A5260A", "Bismarck-furious"}, + {"A52A2A", "Auburn"}, + {"A57164", "Blast-off bronze"}, + {"A67B5B", "Caf? au lait"}, + {"A8516E", "China rose"}, + {"AA381E", "Chinese red"}, + {"AB274F", "Amaranth purple"}, + {"AB381F", "Chinese brown"}, + {"ABCDEF", "Pale cornflower blue"}, + {"ACB78E", "Swamp green"}, + {"ACE1AF", "Celadon"}, + {"ACE5EE", "Blue Lagoon"}, + {"AD6F69", "Copper penny"}, + {"ADDFAD", "Moss green"}, + {"ADFF2F", "Green-yellow"}, + {"AF002A", "Alabama crimson"}, + {"AF4035", "Pale carmine"}, + {"AF6E4D", "Brown Sugar"}, + {"AFEEEE", "Pale Blue"}, + {"B01B2E", "Christmas red"}, + {"B08D57", "Bronze (Metallic)"}, + {"B0BF1A", "Acid green"}, + {"B284BE", "African violet"}, + {"B2BEB5", "Ash gray"}, + {"B31B1B", "Carnelian"}, + {"B32134", "American red"}, + {"B5A642", "Brass"}, + {"B60C26", "Cadmium Purple"}, + {"B7410E", "Rust"}, + {"B87333", "Copper"}, + {"B8860B", "Dark goldenrod"}, + {"BADBAD", "Dark Tea Green"}, + {"BBBBBB", "Light Grey"}, + {"BCD4E6", "Beau blue"}, + {"BD33A4", "Byzantine"}, + {"BDB76B", "Dark Khaki"}, + {"BEF574", "Pistachio"}, + {"BF4F51", "Bittersweet shimmer"}, + {"BF94E4", "Bright lavender"}, + {"BFAFB2", "Black Shadows"}, + {"BFFF00", "Bitter lime"}, + {"C0C0C0", "Silver"}, + {"C19A6B", "Camel"}, + {"C32148", "Bright maroon"}, + {"C39953", "Aztec Gold"}, + {"C3B091", "Khaki"}, + {"C41E3A", "Cardinal"}, + {"C46210", "Alloy orange"}, + {"C4D8E2", "Columbia Blue"}, + {"C71585", "Red-violet"}, + {"C7D0CC", "Gris de perle"}, + {"C7FCEC", "Pang"}, + {"C8A2C8", "Lilac"}, + {"C95A49", "Cedar Chest"}, + {"C9A0DC", "Wisteria"}, + {"C9FFE5", "Aero blue"}, + {"CAA906", "Christmas gold"}, + {"CADABA", "Gray-Tea Green"}, + {"CAE00D", "Bitter lemon"}, + {"CB4154", "Brick red"}, + {"CC0000", "Boston University Red"}, + {"CC5500", "Burnt orange"}, + {"CC7722", "Ochre"}, + {"CC8899", "Puce"}, + {"CC9900", "Chinese gold"}, + {"CC9966", "Brown Yellow"}, + {"CCCCCC", "Chinese silver"}, + {"CCCCFF", "Periwinkle"}, + {"CCFF00", "Lime"}, + {"CD00CD", "Bright violet"}, + {"CD5700", "Tenne"}, + {"CD5B45", "Dark coral"}, + {"CD5C5C", "Chestnut"}, + {"CD607E", "Cinnamon Satin"}, + {"CD7F32", "Bronze"}, + {"CD8032", "Chinese bronze"}, + {"CD853F", "Light brown"}, + {"CD9575", "Antique brass"}, + {"CFB53B", "Old Gold"}, + {"CFCFCF", "American silver"}, + {"D0DB61", "Chinese green"}, + {"D0F0C0", "Tea Green"}, + {"D0FF14", "Arctic lime"}, + {"D1001C", "Blood orange"}, + {"D19FE8", "Bright ube"}, + {"D1E231", "Pear"}, + {"D2691E", "Chocolate"}, + {"D2B48C", "Tan"}, + {"D3212D", "Amaranth red"}, + {"D3AF37", "American gold"}, + {"D53E07", "Titian"}, + {"D5713F", "Vanilla"}, + {"D5D5D5", "Abdel Kerim's beard"}, + {"D77D31", "Reddish-brown"}, + {"D891EF", "Bright lilac"}, + {"D8A903", "Dark pear"}, + {"D8BFD8", "Thistle"}, + {"DA70D6", "Orchid"}, + {"DAA520", "Goldenrod"}, + {"DABDAB", "Pale Sandy Brown"}, + {"DAD871", "Vert-de-pеche"}, + {"DB7093", "Pale red-violet"}, + {"DBE9F4", "Azureish white"}, + {"DC143C", "Crimson"}, + {"DDADAF", "Pale chestnut"}, + {"DDE26A", "Booger Buster"}, + {"DE3163", "Cerise"}, + {"DE5D83", "Blush"}, + {"DE6FA1", "China pink"}, + {"DF73FF", "Heliotrope"}, + {"E0218A", "Barbie pink"}, + {"E1DFE0", "Christmas silver"}, + {"E28B00", "Siena"}, + {"E2E5DE", "Chinese white"}, + {"E30022", "Cadmium red"}, + {"E32636", "Alizarin crimson"}, + {"E34234", "Cinnabar"}, + {"E3DAC9", "Bone"}, + {"E4717A", "Candy pink"}, + {"E49B0F", "Gamboge"}, + {"E4D00A", "Citrine"}, + {"E52B50", "Amaranth"}, + {"E6E6FA", "Lavender"}, + {"E75480", "Dark pink"}, + {"E7FEFF", "Bubbles"}, + {"E88E5A", "Big Foot Feet"}, + {"E97451", "Burnt sienna"}, + {"E9967A", "Dark salmon"}, + {"E9D66B", "Arylide yellow"}, + {"EA8DF7", "Violaceous"}, + {"EB4C42", "Carmine pink"}, + {"EBC2AF", "Zinnwaldite"}, + {"EBECF0", "Bright gray"}, + {"ED872D", "Cadmium orange"}, + {"ED9121", "Carrot"}, + {"EEDC82", "Flax"}, + {"EEE0B1", "Cookies and cream"}, + {"EEE6A3", "Perhydor"}, + {"EFAF8C", "Saumon"}, + {"EFBBCC", "Cameo pink"}, + {"EFDECD", "Almond"}, + {"F0DC82", "Buff"}, + {"F0F8FF", "Alice blue"}, + {"F19CBB", "Amaranth pink"}, + {"F1DDCF", "Champagne pink"}, + {"F28E1C", "Beer"}, + {"F2B400", "American yellow"}, + {"F2E8C9", "Light cream"}, + {"F2F0E6", "Alabaster"}, + {"F2F3F4", "Anti-flash white"}, + {"F37042", "Chinese orange"}, + {"F4A460", "Sandy brown"}, + {"F4BBFF", "Brilliant lavender"}, + {"F4C2C2", "Baby pink"}, + {"F4C430", "Saffron"}, + {"F5DEB3", "Wheat"}, + {"F5F5DC", "Beige"}, + {"F7E7CE", "Champagne"}, + {"F7F21A", "Child's surprise"}, + {"F88379", "Congo pink"}, + {"F984E5", "Pale magenta"}, + {"FA6E79", "Begonia"}, + {"FADADD", "Pale pink"}, + {"FADFAD", "Peach-yellow"}, + {"FAE7B5", "Banana Mania"}, + {"FAEBD7", "Antique white"}, + {"FAEEDD", "Scared nymph"}, + {"FAF0E6", "Linen"}, + {"FB607F", "Brink pink"}, + {"FBCCE7", "Classic rose"}, + {"FBCEB1", "Apricot"}, + {"FBEC5D", "Corn"}, + {"FC0FC0", "Hot pink"}, + {"FD7C6E", "Coral Reef"}, + {"FDE910", "Lemon"}, + {"FDEE00", "Aureolin"}, + {"FE6F5E", "Bittersweet"}, + {"FEF200", "Christmas yellow"}, + {"FEFEFA", "Baby powder"}, + {"FF0000", "Red"}, + {"FF0038", "Carmine red"}, + {"FF007F", "Bright pink"}, + {"FF00FF", "Magenta (Fuchsia)"}, + {"FF033E", "American rose"}, + {"FF0800", "Candy apple red"}, + {"FF2052", "Awesome"}, + {"FF2400", "Scarlet"}, + {"FF47CA", "Shocked star"}, + {"FF4D00", "Vermilion"}, + {"FF4F00", "Safety orange"}, + {"FF55A3", "Brilliant rose"}, + {"FF6600", "Christmas orange"}, + {"FF7518", "Pumpkin"}, + {"FF7E00", "Amber (SAE/ECE)"}, + {"FF7F50", "Coral"}, + {"FF8B00", "American orange"}, + {"FF8C69", "Salmon"}, + {"FF91AF", "Baker-Miller pink"}, + {"FF9218", "Jaco"}, + {"FF9900", "Blaze Orange"}, + {"FF9966", "Pink-orange"}, + {"FFA500", "Orange"}, + {"FFA600", "Cheese"}, + {"FFA6C9", "Carnation pink"}, + {"FFA812", "Dark tangerine"}, + {"FFAA1D", "Bright Yellow (Crayola)"}, + {"FFBA00", "Selective yellow"}, + {"FFBCD9", "Cotton candy"}, + {"FFBF00", "Amber"}, + {"FFC0CB", "Pink"}, + {"FFC1CC", "Bubble gum"}, + {"FFCC00", "Tangerine"}, + {"FFCC99", "Peach-orange"}, + {"FFCCCB", "Christmas pink"}, + {"FFD1DC", "Pastel pink"}, + {"FFD59A", "Caramel"}, + {"FFD700", "Gold"}, + {"FFD800", "School bus yellow"}, + {"FFDAB9", "Dark Peach"}, + {"FFDB58", "Mustard"}, + {"FFDEAD", "Navajo white"}, + {"FFE135", "Banana yellow"}, + {"FFE4B2", "Yellow Pink"}, + {"FFE4C4", "Bisque"}, + {"FFE5B4", "Peach"}, + {"FFEBCD", "Blanched almond"}, + {"FFEF00", "Canary yellow"}, + {"FFEFD5", "Papaya whip"}, + {"FFF0F5", "Lavender Blush"}, + {"FFF5EE", "Seashell"}, + {"FFF600", "Cadmium yellow"}, + {"FFF8DC", "Cornsilk"}, + {"FFF8E7", "Cosmic latte"}, + {"FFFACD", "Lemon Cream"}, + {"FFFDD0", "Cream"}, + {"FFFDDF", "Ivory"}, + {"FFFF00", "Yellow"}, + {"FFFF99", "Canary"}, + {"FFFFCC", "Conditioner"}, + {"FFFFFF", "White"}, + }; + + /// + /// Return a representation of a CMYK color + /// + /// The for the CMYK color presentation + /// A representation of a CMYK color + public static string ColorToCmyk(Color color) + { + var (cyan, magenta, yellow, blackKey) = ColorFormatUtils.ConvertToCmykColor(color); + + cyan = Math.Round(cyan * 100); + magenta = Math.Round(magenta * 100); + yellow = Math.Round(yellow * 100); + blackKey = Math.Round(blackKey * 100); + + return $"cmyk({cyan.ToString(CultureInfo.InvariantCulture)}%" + + $", {magenta.ToString(CultureInfo.InvariantCulture)}%" + + $", {yellow.ToString(CultureInfo.InvariantCulture)}%" + + $", {blackKey.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a hexadecimal representation of a RGB color + /// + /// The for the hexadecimal presentation + /// A hexadecimal representation of a RGB color + public static string ColorToHex(Color color) + { + const string hexFormat = "x2"; + + return $"{color.R.ToString(hexFormat, CultureInfo.InvariantCulture)}" + + $"{color.G.ToString(hexFormat, CultureInfo.InvariantCulture)}" + + $"{color.B.ToString(hexFormat, CultureInfo.InvariantCulture)}"; + } + + /// + /// Return a representation of a HSB color + /// + /// The for the HSB color presentation + /// A representation of a HSB color + public static string ColorToHsb(Color color) + { + var (hue, saturation, brightness) = ColorFormatUtils.ConvertToHsbColor(color); + + hue = Math.Round(hue); + saturation = Math.Round(saturation * 100); + brightness = Math.Round(brightness * 100); + + return $"hsb({hue.ToString(CultureInfo.InvariantCulture)}" + + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + + $", {brightness.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a representation float color styling(0.1f, 0.1f, 0.1f) + /// + /// The to convert + /// a string value (0.1f, 0.1f, 0.1f) + public static string ColorToFloat(Color color) + { + var (red, green, blue) = (color.R / 255d, color.G / 255d, color.B / 255d); + const int precision = 2; + const string floatFormat = "0.##"; + + return $"({Math.Round(red, precision).ToString(floatFormat, CultureInfo.InvariantCulture)}f" + + $", {Math.Round(green, precision).ToString(floatFormat, CultureInfo.InvariantCulture)}f" + + $", {Math.Round(blue, precision).ToString(floatFormat, CultureInfo.InvariantCulture)}f, 1f)"; + } + + /// + /// Return a representation decimal color value + /// + /// The to convert + /// a string value number + public static string ColorToDecimal(Color color) + { + return $"{(color.R * 65536) + (color.G * 256) + color.B}"; + } + + /// + /// Return a representation of a HSI color + /// + /// The for the HSI color presentation + /// A representation of a HSI color + public static string ColorToHsi(Color color) + { + var (hue, saturation, intensity) = ColorFormatUtils.ConvertToHsiColor(color); + + hue = Math.Round(hue); + saturation = Math.Round(saturation * 100); + intensity = Math.Round(intensity * 100); + + return $"hsi({hue.ToString(CultureInfo.InvariantCulture)}" + + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + + $", {intensity.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a representation of a HSL color + /// + /// The for the HSL color presentation + /// A representation of a HSL color + public static string ColorToHsl(Color color) + { + var (hue, saturation, lightness) = ColorFormatUtils.ConvertToHslColor(color); + + hue = Math.Round(hue); + saturation = Math.Round(saturation * 100); + lightness = Math.Round(lightness * 100); + + // Using InvariantCulture since this is used for color representation + return $"hsl({hue.ToString(CultureInfo.InvariantCulture)}" + + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + + $", {lightness.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a representation of a HSV color + /// + /// The for the HSV color presentation + /// A representation of a HSV color + public static string ColorToHsv(Color color) + { + var (hue, saturation, value) = ColorFormatUtils.ConvertToHsvColor(color); + + hue = Math.Round(hue); + saturation = Math.Round(saturation * 100); + value = Math.Round(value * 100); + + // Using InvariantCulture since this is used for color representation + return $"hsv({hue.ToString(CultureInfo.InvariantCulture)}" + + $", {saturation.ToString(CultureInfo.InvariantCulture)}%" + + $", {value.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a representation of a HWB color + /// + /// The for the HWB color presentation + /// A representation of a HWB color + public static string ColorToHwb(Color color) + { + var (hue, whiteness, blackness) = ColorFormatUtils.ConvertToHwbColor(color); + + hue = Math.Round(hue); + whiteness = Math.Round(whiteness * 100); + blackness = Math.Round(blackness * 100); + + return $"hwb({hue.ToString(CultureInfo.InvariantCulture)}" + + $", {whiteness.ToString(CultureInfo.InvariantCulture)}%" + + $", {blackness.ToString(CultureInfo.InvariantCulture)}%)"; + } + + /// + /// Return a representation of a natural color + /// + /// The for the natural color presentation + /// A representation of a natural color + public static string ColorToNCol(Color color) + { + var (hue, whiteness, blackness) = ColorFormatUtils.ConvertToNaturalColor(color); + + whiteness = Math.Round(whiteness * 100); + blackness = Math.Round(blackness * 100); + + return $"{hue}" + + $", {whiteness.ToString(CultureInfo.InvariantCulture)}%" + + $", {blackness.ToString(CultureInfo.InvariantCulture)}%"; + } + + /// + /// Return a representation of a RGB color + /// + /// The for the RGB color presentation + /// A representation of a RGB color + public static string ColorToRgb(Color color) + => $"rgb({color.R.ToString(CultureInfo.InvariantCulture)}" + + $", {color.G.ToString(CultureInfo.InvariantCulture)}" + + $", {color.B.ToString(CultureInfo.InvariantCulture)})"; + + /// + /// Returns a representation of a CIE LAB color + /// + /// The for the CIE LAB color presentation + /// A representation of a CIE LAB color + public static string ColorToCielab(Color color) + { + var (lightness, chromaticityA, chromaticityB) = ColorFormatUtils.ConvertToCielabColor(color); + lightness = Math.Round(lightness, 2); + chromaticityA = Math.Round(chromaticityA, 2); + chromaticityB = Math.Round(chromaticityB, 2); + + return $"CIELab({lightness.ToString(CultureInfo.InvariantCulture)}" + + $", {chromaticityA.ToString(CultureInfo.InvariantCulture)}" + + $", {chromaticityB.ToString(CultureInfo.InvariantCulture)})"; + } + + /// + /// Returns a representation of a CIE XYZ color + /// + /// The for the CIE XYZ color presentation + /// A representation of a CIE XYZ color + public static string ColorToCieXyz(Color color) + { + var (x, y, z) = ColorFormatUtils.ConvertToCiexyzColor(color); + + x = Math.Round(x * 100, 4); + y = Math.Round(y * 100, 4); + z = Math.Round(z * 100, 4); + + return $"XYZ({x.ToString(CultureInfo.InvariantCulture)}" + + $", {y.ToString(CultureInfo.InvariantCulture)}" + + $", {z.ToString(CultureInfo.InvariantCulture)})"; + } + + /// + /// Return a hexadecimal integer representation of a RGB color + /// + /// The for the hexadecimal integer presentation + /// A hexadecimal integer representation of a RGB color + public static string ColorToHexInteger(Color color) + { + const string hexFormat = "X2"; + + return "0xFF" + + $"{color.R.ToString(hexFormat, CultureInfo.InvariantCulture)}" + + $"{color.G.ToString(hexFormat, CultureInfo.InvariantCulture)}" + + $"{color.B.ToString(hexFormat, CultureInfo.InvariantCulture)}"; + } + + /// + /// Return a name of a RGB color + /// + /// The for presentation + /// Approximate name of a color based on RGB representation + public static string GetColorName(Color color) + { + var colorName = string.Empty; + var closestDistance = double.MaxValue; + foreach (var entry in KnownColors) + { + var knownColor = ConvertHexStringToColor(entry.Key); + var distance = CalculateColorDistance(color, knownColor); + + if (distance < closestDistance) + { + colorName = entry.Value; + closestDistance = distance; + } + } + + return colorName; + } + + private static Color ConvertHexStringToColor(string hex) + { + var red = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber); + var green = byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber); + var blue = byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber); + + return Color.FromArgb(red, green, blue); + } + + private static double CalculateColorDistance(Color color1, Color color2) + { + var deltaR = color1.R - color2.R; + var deltaG = color1.G - color2.G; + var deltaB = color1.B - color2.B; + + return Math.Sqrt(deltaR * deltaR + deltaG * deltaG + deltaB * deltaB); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI/Controls/NavigationView/INavigableView.cs b/source/RevitLookup.UI.Abstractions/Controls/INavigableView.cs similarity index 59% rename from source/RevitLookup.UI/Controls/NavigationView/INavigableView.cs rename to source/RevitLookup.UI.Abstractions/Controls/INavigableView.cs index 9cd23d8b7..2a3252163 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/INavigableView.cs +++ b/source/RevitLookup.UI.Abstractions/Controls/INavigableView.cs @@ -3,17 +3,17 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// ReSharper disable once CheckNamespace -namespace Wpf.Ui.Controls; +namespace Wpf.Ui.Abstractions.Controls; /// -/// A component whose ViewModel is separate from the DataContext and can be navigated by . +/// A component whose ViewModel is separate from the DataContext and can be navigated by INavigationView. /// +/// The type of the ViewModel associated with the view. This type optionally may implement to participate in navigation processes. public interface INavigableView { /// - /// ViewModel used by the view. - /// Optionally, it may implement and be navigated by . + /// Gets the view model used by the view. + /// Optionally, it may implement and be navigated by INavigationView. /// T ViewModel { get; } -} +} \ No newline at end of file diff --git a/source/RevitLookup.UI/Controls/NavigationView/INavigationAware.cs b/source/RevitLookup.UI.Abstractions/Controls/INavigationAware.cs similarity index 50% rename from source/RevitLookup.UI/Controls/NavigationView/INavigationAware.cs rename to source/RevitLookup.UI.Abstractions/Controls/INavigationAware.cs index 586aedbd6..50f195af6 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/INavigationAware.cs +++ b/source/RevitLookup.UI.Abstractions/Controls/INavigationAware.cs @@ -3,8 +3,7 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// ReSharper disable once CheckNamespace -namespace Wpf.Ui.Controls; +namespace Wpf.Ui.Abstractions.Controls; /// /// Notifies class about being navigated. @@ -12,12 +11,14 @@ namespace Wpf.Ui.Controls; public interface INavigationAware { /// - /// Method triggered when the class is navigated. + /// Asynchronously handles the event that is fired after the component is navigated to. /// - void OnNavigatedTo(); + /// A task that represents the asynchronous operation. + Task OnNavigatedToAsync(); /// - /// Method triggered when the navigation leaves the current class. + /// Asynchronously handles the event that is fired before the component is navigated from. /// - void OnNavigatedFrom(); -} + /// A task that represents the asynchronous operation. + Task OnNavigatedFromAsync(); +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/Controls/NavigationAware.cs b/source/RevitLookup.UI.Abstractions/Controls/NavigationAware.cs new file mode 100644 index 000000000..3b609ebcd --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/Controls/NavigationAware.cs @@ -0,0 +1,44 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Abstractions.Controls; + +/// +/// Provides a base class for navigation-aware components. +/// +public abstract class NavigationAware : INavigationAware +{ + /// + public virtual Task OnNavigatedToAsync() + { + OnNavigatedTo(); + + return Task.CompletedTask; + } + + /// + /// Handles the event that is fired after the component is navigated to. + /// + // ReSharper disable once MemberCanBeProtected.Global + public virtual void OnNavigatedTo() + { + } + + /// + public virtual Task OnNavigatedFromAsync() + { + OnNavigatedFrom(); + + return Task.CompletedTask; + } + + /// + /// Handles the event that is fired before the component is navigated from. + /// + // ReSharper disable once MemberCanBeProtected.Global + public virtual void OnNavigatedFrom() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/GlobalUsings.cs b/source/RevitLookup.UI.Abstractions/GlobalUsings.cs new file mode 100644 index 000000000..8fcccdc85 --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/GlobalUsings.cs @@ -0,0 +1,7 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +global using System; +global using System.Threading.Tasks; \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/INavigationViewPageProvider.cs b/source/RevitLookup.UI.Abstractions/INavigationViewPageProvider.cs new file mode 100644 index 000000000..cecfeb55b --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/INavigationViewPageProvider.cs @@ -0,0 +1,19 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Abstractions; + +/// +/// Defines a service that provides pages for navigation. +/// +public interface INavigationViewPageProvider +{ + /// + /// Retrieves a page of the specified type. + /// + /// The type of the page to retrieve. + /// An instance of the specified page type, or null if the page is not found. + public object? GetPage(Type pageType); +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/NavigationException.cs b/source/RevitLookup.UI.Abstractions/NavigationException.cs new file mode 100644 index 000000000..1f1eee3b5 --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/NavigationException.cs @@ -0,0 +1,31 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Abstractions; + +/// +/// Represents errors that occur during navigation. +/// +public sealed class NavigationException : Exception +{ + /// + /// Initializes a new instance of the NavigationException class with a specified error message. + /// + /// The message that describes the error. + public NavigationException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the NavigationException class with a specified error message and a reference to the inner exception that is the cause of this exception. + /// + /// The exception that is the cause of the current exception. + /// The message that describes the error. + public NavigationException(Exception e, string message) + : base(message, e) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/NavigationViewPageProviderExtensions.cs b/source/RevitLookup.UI.Abstractions/NavigationViewPageProviderExtensions.cs new file mode 100644 index 000000000..391b53d3c --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/NavigationViewPageProviderExtensions.cs @@ -0,0 +1,39 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Abstractions; + +/// +/// Provides extension methods for the INavigationViewPageProvider interface. +/// +public static class NavigationViewPageProviderExtensions +{ + /// + /// Retrieves a page of the specified type from the page service. + /// + /// The type of the page to retrieve. + /// The page service instance. + /// An instance of the specified page type, or null if the page is not found. + public static TPage? GetPage(this INavigationViewPageProvider navigationViewPageProvider) + where TPage : class + { + return navigationViewPageProvider.GetPage(typeof(TPage)) as TPage; + } + + /// + /// Retrieves a page of the specified type from the page service. + /// Throws a NavigationException if the page is not found. + /// + /// The type of the page to retrieve. + /// The page service instance. + /// An instance of the specified page type. + /// Thrown when the specified page type is not found. + public static TPage GetRequiredPage(this INavigationViewPageProvider navigationViewPageProvider) + where TPage : class + { + return navigationViewPageProvider.GetPage(typeof(TPage)) as TPage + ?? throw new NavigationException($"{typeof(TPage)} page not found."); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Abstractions/RevitLookup.UI.Abstractions.csproj b/source/RevitLookup.UI.Abstractions/RevitLookup.UI.Abstractions.csproj new file mode 100644 index 000000000..8aa86de68 --- /dev/null +++ b/source/RevitLookup.UI.Abstractions/RevitLookup.UI.Abstractions.csproj @@ -0,0 +1,9 @@ + + + + true + net48;net8.0-windows + Wpf.Ui.Abstractions + + + diff --git a/source/RevitLookup.UI.Demo/App.xaml b/source/RevitLookup.UI.Demo/App.xaml deleted file mode 100644 index 20afa7405..000000000 --- a/source/RevitLookup.UI.Demo/App.xaml +++ /dev/null @@ -1,7 +0,0 @@ - - \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/App.xaml.cs b/source/RevitLookup.UI.Demo/App.xaml.cs deleted file mode 100644 index 495e06a9f..000000000 --- a/source/RevitLookup.UI.Demo/App.xaml.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.IO; -using System.Reflection; -using System.Windows; -using RevitLookup.Services.Contracts; -using RevitLookup.Views.Pages; - -namespace RevitLookup.UI.Demo; - -public sealed partial class App -{ - private string _revitPath; - - private void OnStartup(object sender, StartupEventArgs e) - { - AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve; - var host = HostProvider.CreateHost(); - - Host.StartProxy(host); - Host.GetService().Show(); - } - - private void OnExit(object sender, ExitEventArgs e) - { - var settingsService = Host.GetService(); - settingsService.SaveSettings(); - - Host.Stop(); - } - - private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) - { - var assemblyName = new AssemblyName(args.Name); - _revitPath ??= $@"C:\Program Files\Autodesk\Revit 20{assemblyName.Version!.Major}"; - if (!Directory.Exists(_revitPath)) return null; - - var assemblyPath = Path.Combine(_revitPath, $"{assemblyName.Name}.dll"); - if (!File.Exists(assemblyPath)) return null; - - return Assembly.LoadFrom(assemblyPath); - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/HostProvider.cs b/source/RevitLookup.UI.Demo/HostProvider.cs deleted file mode 100644 index 32489388a..000000000 --- a/source/RevitLookup.UI.Demo/HostProvider.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.IO; -using System.Reflection; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using RevitLookup.Config; -using RevitLookup.Services; -using RevitLookup.Services.Contracts; -using RevitLookup.UI.Demo.Mock.Services; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.ViewModels.Pages; -using RevitLookup.Views; -using RevitLookup.Views.Pages; -using Wpf.Ui; -using MockDashboardViewModel = RevitLookup.UI.Demo.Mock.ViewModels.MockDashboardViewModel; -using MockEventsViewModel = RevitLookup.UI.Demo.Mock.ViewModels.MockEventsViewModel; -using MockSnoopViewModel = RevitLookup.UI.Demo.Mock.ViewModels.MockSnoopViewModel; - -namespace RevitLookup.UI.Demo; - -public static class HostProvider -{ - public static IHost CreateHost() - { - var builder = new HostApplicationBuilder(new HostApplicationBuilderSettings - { - ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly()!.Location), - DisableDefaults = true - }); - - //Logging - builder.Logging.ClearProviders(); - builder.Logging.AddSerilogConfiguration(); - - //Configuration - builder.Services.AddOptions(builder.Configuration); - - //App services - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - - //UI services - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - //Views - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - - //Startup view - builder.Services.AddTransient(); - - return builder.Build(); - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/Mock/Services/MockLookupService.cs b/source/RevitLookup.UI.Demo/Mock/Services/MockLookupService.cs deleted file mode 100644 index e6d520af9..000000000 --- a/source/RevitLookup.UI.Demo/Mock/Services/MockLookupService.cs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Windows; -using System.Windows.Controls; -using Microsoft.Extensions.DependencyInjection; -using RevitLookup.Core.Objects; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using Wpf.Ui; - -namespace RevitLookup.UI.Demo.Mock.Services; - -public sealed class MockLookupService(IServiceScopeFactory scopeFactory) : ILookupService -{ - private Window _owner; - private Task _activeTask; - private readonly IServiceScope _scope = scopeFactory.CreateScope(); - - public ILookupServiceDependsStage Snoop(SnoopableType snoopableType) - { - _activeTask = _scope.ServiceProvider.GetRequiredService()!.SnoopAsync(snoopableType); - return this; - } - - public ILookupServiceDependsStage Snoop(SnoopableObject snoopableObject) - { - _scope.ServiceProvider.GetRequiredService()!.Snoop(snoopableObject); - return this; - } - - public ILookupServiceDependsStage Snoop(IList snoopableObjects) - { - _scope.ServiceProvider.GetRequiredService()!.Snoop(snoopableObjects); - return this; - } - - public ILookupServiceShowStage DependsOn(IServiceProvider provider) - { - _owner = (Window)provider.GetService(); - return this; - } - - public ILookupServiceExecuteStage Show() where T : Page - { - if (_activeTask is null) - { - ShowPage(); - } - else - { - _activeTask = _activeTask.ContinueWith(_ => ShowPage(), TaskScheduler.FromCurrentSynchronizationContext()); - } - - return this; - } - - public void Execute(Action handler) where T : class - { - if (_activeTask is null) - { - InvokeHandler(handler); - } - else - { - _activeTask = _activeTask.ContinueWith(_ => InvokeHandler(handler), TaskScheduler.FromCurrentSynchronizationContext()); - } - } - - private void ShowPage() where T : Page - { - var window = (Window)_scope.ServiceProvider.GetRequiredService(); - window.Closed += OnWindowClosed; - - if (_owner is null) - { - window.WindowStartupLocation = WindowStartupLocation.CenterScreen; - } - else - { - window.Left = _owner.Left + 47; - window.Top = _owner.Top + 49; - } - - window.Show(); - _scope.ServiceProvider.GetRequiredService().Navigate(typeof(T)); - } - - private void InvokeHandler(Action handler) where T : class - { - var service = _scope.ServiceProvider.GetRequiredService(); - handler.Invoke(service); - } - - private void OnWindowClosed(object sender, EventArgs e) - { - _scope.Dispose(); - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/Mock/Services/MockSnoopVisualService.cs b/source/RevitLookup.UI.Demo/Mock/Services/MockSnoopVisualService.cs deleted file mode 100644 index 0de6438cc..000000000 --- a/source/RevitLookup.UI.Demo/Mock/Services/MockSnoopVisualService.cs +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using Autodesk.Revit.DB; -using Bogus; -using RevitLookup.Core.Contracts; -using RevitLookup.Core.Objects; -using RevitLookup.Core.Utils; -using RevitLookup.Services; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.ViewModels.Contracts; -using Visibility = System.Windows.Visibility; - -namespace RevitLookup.UI.Demo.Mock.Services; - -public sealed class MockSnoopVisualService(NotificationService notificationService, ISnoopViewModel viewModel, IWindow window) : ISnoopVisualService -{ - public void Snoop(SnoopableObject snoopableObject) - { - try - { - if (snoopableObject.Descriptor is IDescriptorEnumerator { IsEmpty: false } descriptor) - { - viewModel.SnoopableObjects = descriptor.ParseEnumerable(snoopableObject); - } - else - { - viewModel.SnoopableObjects = new[] { snoopableObject }; - } - - viewModel.SnoopableData = Array.Empty(); - } - catch (Exception exception) - { - notificationService.ShowError("Invalid object", exception); - } - } - - public void Snoop(IList snoopableObjects) - { - viewModel.SnoopableObjects = snoopableObjects; - viewModel.SnoopableData = Array.Empty(); - } - - public async Task SnoopAsync(SnoopableType snoopableType) - { - switch (snoopableType) - { - case SnoopableType.Face: - case SnoopableType.Edge: - case SnoopableType.LinkedElement: - case SnoopableType.Point: - case SnoopableType.SubElement: - UpdateWindowVisibility(Visibility.Hidden); - await Task.Delay(TimeSpan.FromSeconds(2)); - break; - } - - var generationCount = snoopableType switch - { - SnoopableType.View => 50_000, - SnoopableType.Document => 25_000, - SnoopableType.Application => 10_000, - SnoopableType.UiApplication => 5_000, - SnoopableType.Database => 2_000, - SnoopableType.DependentElements => 1_000, - SnoopableType.Selection => 500, - SnoopableType.LinkedElement => 250, - SnoopableType.Face => 125, - SnoopableType.Edge => 60, - SnoopableType.Point => 30, - SnoopableType.SubElement => 15, - SnoopableType.ComponentManager => 8, - SnoopableType.PerformanceAdviser => 4, - SnoopableType.UpdaterRegistry => 2, - SnoopableType.Services => 1, - SnoopableType.Schemas => 0, - _ => throw new ArgumentOutOfRangeException(nameof(snoopableType), snoopableType, null) - }; - - var items = await GenerateObjectsAsync(generationCount); - Snoop(items); - UpdateWindowVisibility(Visibility.Visible); - } - - private void UpdateWindowVisibility(Visibility visibility) - { - if (!window.IsLoaded) return; - - window.Visibility = visibility; - } - - private static async Task> GenerateObjectsAsync(int generationCount) - { - if (generationCount == 0) return Array.Empty(); - - return await Task.Run(() => new Faker() - .CustomInstantiator(faker => - { - if (faker.IndexFaker % 2000 == 0) return new SnoopableObject((object)null); - if (faker.IndexFaker % 1000 == 0) return new SnoopableObject(string.Empty); - if (faker.IndexFaker % 700 == 0) return new SnoopableObject(faker.Make(150, () => faker.Internet.UserName())); - if (faker.IndexFaker % 500 == 0) return new SnoopableObject(typeof(DateTime)); - if (faker.IndexFaker % 200 == 0) return new SnoopableObject(faker.Lorem.Sentence()); - if (faker.IndexFaker % 100 == 0) return new SnoopableObject(faker.Make(150, () => new Color(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()))); - if (faker.IndexFaker % 5 == 0) return new SnoopableObject(faker.Random.Int(0)); - if (faker.IndexFaker % 3 == 0) return new SnoopableObject(faker.Random.Bool()); - - return new SnoopableObject(faker.Lorem.Word()); - }) - .Generate(generationCount)); - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockDashboardViewModel.cs b/source/RevitLookup.UI.Demo/Mock/ViewModels/MockDashboardViewModel.cs deleted file mode 100644 index af530954c..000000000 --- a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockDashboardViewModel.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.Views.Dialogs; -using RevitLookup.Views.Pages; -using Wpf.Ui; - -namespace RevitLookup.UI.Demo.Mock.ViewModels; - -public partial class MockDashboardViewModel( - INavigationService navigationService, - ISnoopVisualService snoopVisualService, - IServiceProvider serviceProvider) - : ObservableObject, IDashboardViewModel -{ - [RelayCommand] - private async Task NavigateSnoopPage(string parameter) - { - switch (parameter) - { - case "view": - await snoopVisualService.SnoopAsync(SnoopableType.View); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "document": - await snoopVisualService.SnoopAsync(SnoopableType.Document); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "application": - await snoopVisualService.SnoopAsync(SnoopableType.Application); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "uiApplication": - await snoopVisualService.SnoopAsync(SnoopableType.UiApplication); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "database": - await snoopVisualService.SnoopAsync(SnoopableType.Database); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "dependents": - await snoopVisualService.SnoopAsync(SnoopableType.DependentElements); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "selection": - await snoopVisualService.SnoopAsync(SnoopableType.Selection); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "linked": - await snoopVisualService.SnoopAsync(SnoopableType.LinkedElement); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "face": - await snoopVisualService.SnoopAsync(SnoopableType.Face); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "edge": - await snoopVisualService.SnoopAsync(SnoopableType.Edge); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "point": - await snoopVisualService.SnoopAsync(SnoopableType.Point); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "subElement": - await snoopVisualService.SnoopAsync(SnoopableType.SubElement); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "components": - await snoopVisualService.SnoopAsync(SnoopableType.ComponentManager); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "performance": - await snoopVisualService.SnoopAsync(SnoopableType.PerformanceAdviser); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "updaters": - await snoopVisualService.SnoopAsync(SnoopableType.UpdaterRegistry); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "services": - await snoopVisualService.SnoopAsync(SnoopableType.Services); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "schemas": - await snoopVisualService.SnoopAsync(SnoopableType.Schemas); - navigationService.Navigate(typeof(SnoopPage)); - break; - case "events": - navigationService.Navigate(typeof(EventsPage)); - break; - default: - throw new ArgumentOutOfRangeException(nameof(parameter), parameter); - } - } - - [RelayCommand] - private Task OpenDialog(string parameter) - { - switch (parameter) - { - case "parameters": - var unitsDialog = new UnitsDialog(serviceProvider); - return unitsDialog.ShowParametersAsync(); - case "categories": - unitsDialog = new UnitsDialog(serviceProvider); - return unitsDialog.ShowCategoriesAsync(); - case "forge": - unitsDialog = new UnitsDialog(serviceProvider); - return unitsDialog.ShowForgeSchemaAsync(); - case "search": - var searchDialog = new SearchElementsDialog(serviceProvider); - return searchDialog.ShowAsync(); - case "modules": - var modulesDialog = new ModulesDialog(serviceProvider); - return modulesDialog.ShowAsync(); - } - - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockEventsViewModel.cs b/source/RevitLookup.UI.Demo/Mock/ViewModels/MockEventsViewModel.cs deleted file mode 100644 index f98cb49ac..000000000 --- a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockEventsViewModel.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System.Windows.Media; -using Bogus; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using RevitLookup.Core.Enums; -using RevitLookup.Core.Objects; -using RevitLookup.Services; -using RevitLookup.Services.Contracts; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.ViewModels.Utils; -using RevitLookup.Views.Pages; - -namespace RevitLookup.UI.Demo.Mock.ViewModels; - -public sealed partial class MockEventsViewModel( - NotificationService notificationService, - IServiceProvider provider) - : ObservableObject, IEventsViewModel -{ - private readonly CancellationTokenSource _cancellationTokenSource = new(); - private readonly Stack _events = new(); - - [ObservableProperty] private string _searchText = string.Empty; - [ObservableProperty] private IList _snoopableObjects = []; - [ObservableProperty] private IList _filteredSnoopableObjects = []; - [ObservableProperty] private IList _filteredSnoopableData; - [ObservableProperty] private IList _snoopableData; - - public SnoopableObject SelectedObject { get; set; } - public IServiceProvider ServiceProvider { get; } = provider; - - public void Navigate(SnoopableObject selectedItem) - { - Host.GetService() - .Snoop(selectedItem) - .DependsOn(ServiceProvider) - .Show(); - } - - public void Navigate(IList selectedItems) - { - Host.GetService() - .Snoop(selectedItems) - .DependsOn(ServiceProvider) - .Show(); - } - - public void RemoveObject(object obj) - { - var snoopableObject = obj switch - { - SnoopableObject snoopable => snoopable, - Descriptor descriptor => descriptor.Value.Descriptor.Value, - _ => throw new NotSupportedException($"Type {obj.GetType().Name} removing not supported") - }; - - SnoopableObjects.Remove(snoopableObject); - FilteredSnoopableObjects.Remove(snoopableObject); - } - - partial void OnSearchTextChanged(string value) - { - UpdateSearchResults(SearchOption.Objects); - } - - partial void OnSnoopableObjectsChanged(IList value) - { - SelectedObject = null; - UpdateSearchResults(SearchOption.Objects); - } - - partial void OnSnoopableDataChanged(IList value) - { - UpdateSearchResults(SearchOption.Selection); - } - - private void UpdateSearchResults(SearchOption option) - { - Task.Run(() => - { - if (string.IsNullOrEmpty(SearchText)) - { - FilteredSnoopableObjects = SnoopableObjects; - FilteredSnoopableData = SnoopableData; - return; - } - - var results = SearchEngine.Search(this, option); - if (results.Data is not null) FilteredSnoopableData = results.Data; - if (results.Objects is not null) FilteredSnoopableObjects = results.Objects; - }); - } - - [RelayCommand] - private Task FetchMembersAsync() - { - CollectMembers(true); - return Task.CompletedTask; - } - - [RelayCommand] - private Task RefreshMembersAsync() - { - CollectMembers(false); - return Task.CompletedTask; - } - - private void CollectMembers(bool useCached) - { - if (SelectedObject is null) - { - SnoopableData = Array.Empty(); - return; - } - - try - { - // ReSharper disable once MethodHasAsyncOverload - SnoopableData = SelectedObject.GetMembers(); - } - catch (Exception exception) - { - notificationService.ShowError("Snoop engine error", exception); - } - } - - public void OnNavigatedTo() - { - PushEvents(_cancellationTokenSource.Token); - } - - public void OnNavigatedFrom() - { - _cancellationTokenSource.Cancel(); - } - - private void PushEvents(CancellationToken cancellationToken) - { - Task.Run((Func)(async () => - { - var iteration = 0; - var faker = new Faker(); - while (!cancellationToken.IsCancellationRequested) - { - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - - var snoopableObject = GenerateEvent(faker, iteration); - _events.Push(snoopableObject); - SnoopableObjects = new List(_events); - iteration++; - } - }), cancellationToken); - } - - private static SnoopableObject GenerateEvent(Faker faker, int iteration) - { - if (iteration % 5 == 0) return new SnoopableObject(typeof(DateTime)); - if (iteration % 4 == 0) return new SnoopableObject(Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte())); - if (iteration % 3 == 0) return new SnoopableObject(faker.Random.Int(0)); - if (iteration % 2 == 0) return new SnoopableObject(faker.Random.Bool()); - return new SnoopableObject(faker.Lorem.Word()); - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockSnoopViewModel.cs b/source/RevitLookup.UI.Demo/Mock/ViewModels/MockSnoopViewModel.cs deleted file mode 100644 index f7db44835..000000000 --- a/source/RevitLookup.UI.Demo/Mock/ViewModels/MockSnoopViewModel.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Collections.ObjectModel; -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; -using RevitLookup.Core.Enums; -using RevitLookup.Core.Objects; -using RevitLookup.Services; -using RevitLookup.Services.Contracts; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.ViewModels.Utils; -using RevitLookup.Views.Pages; - -namespace RevitLookup.UI.Demo.Mock.ViewModels; - -public sealed partial class MockSnoopViewModel(NotificationService notificationService, IServiceProvider provider) : ObservableObject, ISnoopViewModel -{ - private Task _updatingTask = Task.CompletedTask; - - [ObservableProperty] private string _searchText = string.Empty; - [ObservableProperty] private IList _snoopableObjects = []; - [ObservableProperty] private IList _filteredSnoopableObjects = []; - [ObservableProperty] private IList _filteredSnoopableData; - [ObservableProperty] private IList _snoopableData; - - public SnoopableObject SelectedObject { get; set; } - public IServiceProvider ServiceProvider { get; } = provider; - - public void Navigate(SnoopableObject selectedItem) - { - Host.GetService() - .Snoop(selectedItem) - .DependsOn(ServiceProvider) - .Show(); - } - - public void Navigate(IList selectedItems) - { - Host.GetService() - .Snoop(selectedItems) - .DependsOn(ServiceProvider) - .Show(); - } - - async partial void OnSearchTextChanged(string value) - { - await _updatingTask; - UpdateSearchResults(SearchOption.Objects); - } - - async partial void OnSnoopableObjectsChanged(IList value) - { - SelectedObject = null; - await _updatingTask; - UpdateSearchResults(SearchOption.Objects); - } - - async partial void OnSnoopableDataChanged(IList value) - { - await _updatingTask; - UpdateSearchResults(SearchOption.Selection); - } - - private void UpdateSearchResults(SearchOption option) - { - _updatingTask = Task.Run(() => - { - if (string.IsNullOrEmpty(SearchText)) - { - if (option == SearchOption.Objects) - { - FilteredSnoopableObjects = SnoopableObjects; - } - - FilteredSnoopableData = SnoopableData; - return; - } - - var results = SearchEngine.Search(this, option); - if (results.Data is not null) FilteredSnoopableData = results.Data; - if (results.Objects is not null) FilteredSnoopableObjects = new ObservableCollection(results.Objects); - }); - } - - public void RemoveObject(object obj) - { - var snoopableObject = obj switch - { - SnoopableObject snoopable => snoopable, - Descriptor descriptor => descriptor.Value.Descriptor.Value, - _ => throw new NotSupportedException($"Type {obj.GetType().Name} removing not supported") - }; - - SnoopableObjects.Remove(snoopableObject); - FilteredSnoopableObjects.Remove(snoopableObject); - } - - [RelayCommand] - private Task FetchMembersAsync() - { - CollectMembers(true); - return Task.CompletedTask; - } - - [RelayCommand] - private Task RefreshMembersAsync() - { - CollectMembers(false); - return Task.CompletedTask; - } - - private void CollectMembers(bool useCached) - { - if (SelectedObject is null) - { - SnoopableData = Array.Empty(); - return; - } - - try - { - // ReSharper disable once MethodHasAsyncOverload - SnoopableData = SelectedObject.GetMembers(); - } - catch (Exception exception) - { - notificationService.ShowError("Snoop engine error", exception); - } - } -} \ No newline at end of file diff --git a/source/RevitLookup.UI.Demo/RevitLookup.UI.Demo.csproj b/source/RevitLookup.UI.Demo/RevitLookup.UI.Demo.csproj deleted file mode 100644 index b6e68b571..000000000 --- a/source/RevitLookup.UI.Demo/RevitLookup.UI.Demo.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - true - WinExe - latest - x64 - true - net8.0-windows - - - - true - full - $(DefineConstants);DEBUG - - - true - none - $(DefineConstants);RELEASE - - - - - - - - - - - - - diff --git a/source/RevitLookup.UI.Framework/App.xaml b/source/RevitLookup.UI.Framework/App.xaml new file mode 100644 index 000000000..e0914cacd --- /dev/null +++ b/source/RevitLookup.UI.Framework/App.xaml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/App.xaml.cs b/source/RevitLookup.UI.Framework/App.xaml.cs new file mode 100644 index 000000000..f428252d5 --- /dev/null +++ b/source/RevitLookup.UI.Framework/App.xaml.cs @@ -0,0 +1,3 @@ +namespace RevitLookup.UI.Framework; + +public partial class App; \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Controls/Automation/NoAutomationWindowPeer.cs b/source/RevitLookup.UI.Framework/Controls/Automation/NoAutomationWindowPeer.cs new file mode 100644 index 000000000..ba5a8a921 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Controls/Automation/NoAutomationWindowPeer.cs @@ -0,0 +1,18 @@ +using System.Windows; +using System.Windows.Automation.Peers; + +namespace RevitLookup.UI.Framework.Controls.Automation; + +/// +/// Windows peer disabling automation. Removes freezes when using Tooltip, Popup +/// +/// +/// https://github.com/dotnet/wpf/issues/5807 +/// +public sealed class NoAutomationWindowPeer(Window owner) : WindowAutomationPeer(owner) +{ + protected override List GetChildrenCore() + { + return []; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Views/Controls/ColorPicker/ColorPickerControl.xaml b/source/RevitLookup.UI.Framework/Controls/ColorPicker/ColorPickerControl.xaml similarity index 99% rename from source/RevitLookup/Views/Controls/ColorPicker/ColorPickerControl.xaml rename to source/RevitLookup.UI.Framework/Controls/ColorPicker/ColorPickerControl.xaml index e2d0e73b9..d2b328b6f 100644 --- a/source/RevitLookup/Views/Controls/ColorPicker/ColorPickerControl.xaml +++ b/source/RevitLookup.UI.Framework/Controls/ColorPicker/ColorPickerControl.xaml @@ -1,5 +1,5 @@  (Color) GetValue(SelectedColorProperty); set => SetValue(SelectedColorProperty, value); } - + private static void SelectedColorPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { var control = (ColorPickerControl) dependencyObject; var newColor = (Color) e.NewValue; - + control._originalColor = control._currentColor = newColor; var newColorBackground = new SolidColorBrush(newColor); control.CurrentColorButton.Background = newColorBackground; - + control._ignoreHexChanges = true; control._ignoreRgbChanges = true; - + control.HexCode.Text = ColorToHex(newColor); control.RNumberBox.Value = newColor.R; control.GNumberBox.Value = newColor.G; control.BNumberBox.Value = newColor.B; control.SetColorFromTextBoxes(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B)); - + control._ignoreRgbChanges = false; control._ignoreHexChanges = false; - + var hsv = ColorFormatUtils.ConvertToHsvColor(System.Drawing.Color.FromArgb(newColor.R, newColor.G, newColor.B)); SetColorVariationsForCurrentColor(dependencyObject, hsv); } - + private void UpdateHueGradient(double saturation, double value) { var g6 = HsvColor.HueSpectrum(saturation, value); - + var gradientBrush = new LinearGradientBrush { StartPoint = new Point(0, 0), EndPoint = new Point(1, 0) }; - + for (var i = 0; i < g6.Length; i++) { var stop = new GradientStop(g6[i], i * 0.16); gradientBrush.GradientStops.Add(stop); } - + HueGradientSlider.Background = gradientBrush; } - + private static void SetColorVariationsForCurrentColor(DependencyObject d, (double Hue, double Saturation, double Value) hsv) { var hueCoefficient = 0; @@ -97,58 +99,58 @@ private static void SetColorVariationsForCurrentColor(DependencyObject d, (doubl { hueCoefficient = 1; } - + if (hsv.Value - 0.3 < 0) { hueCoefficient2 = 1; } - + var s = hsv.Saturation; var control = (ColorPickerControl) d; - + control.ColorVariation1Button.Background = new SolidColorBrush(HsvColor.RgbFromHsv(Math.Min(hsv.Hue + (hueCoefficient * 8), 360), s, Math.Min(hsv.Value + 0.3, 1))); control.ColorVariation2Button.Background = new SolidColorBrush(HsvColor.RgbFromHsv(Math.Min(hsv.Hue + (hueCoefficient * 4), 360), s, Math.Min(hsv.Value + 0.15, 1))); - + control.ColorVariation3Button.Background = new SolidColorBrush(HsvColor.RgbFromHsv(Math.Max(hsv.Hue - (hueCoefficient2 * 4), 0), s, Math.Max(hsv.Value - 0.2, 0))); control.ColorVariation4Button.Background = new SolidColorBrush(HsvColor.RgbFromHsv(Math.Max(hsv.Hue - (hueCoefficient2 * 8), 0), s, Math.Max(hsv.Value - 0.3, 0))); } - + private void UpdateValueColorGradient(double posX) { ValueGradientSlider.Value = posX; - + _currV = posX / ValueGradientSlider.Maximum; - + UpdateHueGradient(_currS, _currV); - + SaturationStartColor.Color = HsvColor.RgbFromHsv(_currH, 0f, _currV); SaturationStopColor.Color = HsvColor.RgbFromHsv(_currH, 1f, _currV); } - + private void UpdateSaturationColorGradient(double posX) { SaturationGradientSlider.Value = posX; - + _currS = posX / HueGradientSlider.Maximum; - + UpdateHueGradient(_currS, _currV); - + ValueStartColor.Color = HsvColor.RgbFromHsv(_currH, _currS, 0f); ValueStopColor.Color = HsvColor.RgbFromHsv(_currH, _currS, 1f); } - + private void UpdateHueColorGradient(double posX) { HueGradientSlider.Value = posX; _currH = posX / HueGradientSlider.Maximum * 360; - + SaturationStartColor.Color = HsvColor.RgbFromHsv(_currH, 0f, _currV); SaturationStopColor.Color = HsvColor.RgbFromHsv(_currH, 1f, _currV); - + ValueStartColor.Color = HsvColor.RgbFromHsv(_currH, _currS, 0f); ValueStopColor.Color = HsvColor.RgbFromHsv(_currH, _currS, 1f); } - + private void UpdateTextBoxesAndCurrentColor(Color currentColor) { if (!_ignoreHexChanges) @@ -156,90 +158,90 @@ private void UpdateTextBoxesAndCurrentColor(Color currentColor) // Second parameter is set to keep the hashtag if typed by the user before HexCode.Text = ColorToHex(currentColor, HexCode.Text); } - + if (!_ignoreRgbChanges) { RNumberBox.Value = currentColor.R; GNumberBox.Value = currentColor.G; BNumberBox.Value = currentColor.B; } - + _currentColor = currentColor; CurrentColorButton.Background = new SolidColorBrush(currentColor); } - + private void OnCurrentColorButtonClicked(object sender, RoutedEventArgs e) { ShowDetails(); } - + private void ShowDetails() { if (_isCollapsed) { _isCollapsed = false; - + var resizeColor = new DoubleAnimation(256, new Duration(TimeSpan.FromMilliseconds(250))) { EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseInOut} }; - + var moveColor = new ThicknessAnimation(new Thickness(0), new Duration(TimeSpan.FromMilliseconds(250))) { EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseInOut} }; - + CurrentColorButton.BeginAnimation(WidthProperty, resizeColor); CurrentColorButton.BeginAnimation(MarginProperty, moveColor); CurrentColorButton.IsEnabled = false; DetailsFlyout.IsOpen = true; } } - + private void HideDetails() { if (_isCollapsed) return; - + _isCollapsed = true; - + var resizeColor = new DoubleAnimation(165, new Duration(TimeSpan.FromMilliseconds(150))) { EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseInOut} }; - + var moveColor = new ThicknessAnimation(new Thickness(72, 0, 72, 0), new Duration(TimeSpan.FromMilliseconds(150))) { EasingFunction = new ExponentialEase {EasingMode = EasingMode.EaseInOut} }; - + CurrentColorButton.BeginAnimation(WidthProperty, resizeColor); CurrentColorButton.BeginAnimation(MarginProperty, moveColor); CurrentColorButton.IsEnabled = true; } - + private void OnOkButtonClicked(object sender, RoutedEventArgs e) { SelectedColor = _currentColor; DetailsFlyout.Hide(); } - + private void OnDetailsFlyoutClosed(object sender, object e) { HideDetails(); - + // Revert to original color var originalColorBackground = new SolidColorBrush(_originalColor); CurrentColorButton.Background = originalColorBackground; - + HexCode.Text = ColorToHex(_originalColor); } - + private void OnColorVariationButtonClicked(object sender, RoutedEventArgs e) { - var selectedColor = ((SolidColorBrush) ((System.Windows.Controls.Button) sender).Background).Color; + var selectedColor = ((SolidColorBrush) ((Button) sender).Background).Color; SelectedColor = selectedColor; } - + private void OnSaturationGradientSliderValueChanged(object sender, RoutedPropertyChangedEventArgs e) { UpdateSaturationColorGradient(((Slider) sender).Value); @@ -247,7 +249,7 @@ private void OnSaturationGradientSliderValueChanged(object sender, RoutedPropert UpdateTextBoxesAndCurrentColor(HsvColor.RgbFromHsv(_currH, _currS, _currV)); _ignoreGradientsChanges = false; } - + private void OnHueGradientSliderValueChanged(object sender, RoutedPropertyChangedEventArgs e) { UpdateHueColorGradient(((Slider) sender).Value); @@ -255,7 +257,7 @@ private void OnHueGradientSliderValueChanged(object sender, RoutedPropertyChange UpdateTextBoxesAndCurrentColor(HsvColor.RgbFromHsv(_currH, _currS, _currV)); _ignoreGradientsChanges = false; } - + private void OnValueGradientSliderValueChanged(object sender, RoutedPropertyChangedEventArgs e) { UpdateValueColorGradient(((Slider) sender).Value); @@ -263,37 +265,37 @@ private void OnValueGradientSliderValueChanged(object sender, RoutedPropertyChan UpdateTextBoxesAndCurrentColor(HsvColor.RgbFromHsv(_currH, _currS, _currV)); _ignoreGradientsChanges = false; } - + private void OnHexCodeTextChanged(object sender, TextChangedEventArgs e) { var newValue = ((TextBox) sender).Text; - + // support hex with 3 and 6 characters and optional with hashtag var reg = new Regex("^#?([0-9A-Fa-f]{3}){1,2}$"); - + if (!reg.IsMatch(newValue)) { return; } - + if (_ignoreHexChanges) return; - - var converter = new System.Drawing.ColorConverter(); - + + var converter = new ColorConverter(); + // "FormatHexColorString()" is needed to add hashtag if missing and to convert the hex code from three to six characters. Without this we get format exceptions and incorrect color values. var color = (System.Drawing.Color) converter.ConvertFromString(FormatHexColorString(HexCode.Text))!; - + _ignoreHexChanges = true; SetColorFromTextBoxes(color); _ignoreHexChanges = false; } - + private void SetColorFromTextBoxes(System.Drawing.Color color) { if (!_ignoreGradientsChanges) { var hsv = ColorFormatUtils.ConvertToHsvColor(color); - + var huePosition = (hsv.Hue / 360) * HueGradientSlider.Maximum; var saturationPosition = hsv.Saturation * SaturationGradientSlider.Maximum; var valuePosition = hsv.Value * ValueGradientSlider.Maximum; @@ -301,10 +303,10 @@ private void SetColorFromTextBoxes(System.Drawing.Color color) UpdateSaturationColorGradient(saturationPosition); UpdateValueColorGradient(valuePosition); } - + UpdateTextBoxesAndCurrentColor(Color.FromRgb(color.R, color.G, color.B)); } - + private static string ColorToHex(Color color, string oldValue = "") { #if NETCOREAPP @@ -313,7 +315,7 @@ private static string ColorToHex(Color color, string oldValue = "") var newHexString = BitConverter.ToString([color.R, color.G, color.B]).Replace("-", string.Empty); #endif newHexString = newHexString.ToLowerInvariant(); - + // Return only with hashtag if user typed it before #if NETCOREAPP var addHashtag = oldValue.StartsWith('#'); @@ -322,7 +324,7 @@ private static string ColorToHex(Color color, string oldValue = "") #endif return addHashtag ? "#" + newHexString : newHexString; } - + /// /// Formats the hex code string to be accepted by . We are adding hashtag at the beginning if needed and convert from three characters to six characters code. /// @@ -335,7 +337,7 @@ private static string FormatHexColorString(string hexCodeText) // Hex with or without hashTag and three characters return Regex.Replace(hexCodeText, "^#?([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$", "#$1$1$2$2$3$3"); } - + // Hex with or without hashTag and six characters #if NETCOREAPP return hexCodeText.StartsWith('#') ? hexCodeText : "#" + hexCodeText; @@ -343,31 +345,31 @@ private static string FormatHexColorString(string hexCodeText) return hexCodeText.StartsWith("#") ? hexCodeText : "#" + hexCodeText; #endif } - + private void OnHexCodeGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { ((TextBox) sender).SelectAll(); } - + private void OnRgbNumberBoxTextChanged(object sender, TextChangedEventArgs e) { if (_ignoreRgbChanges) return; - + var numberBox = (NumberBox) sender; - + if (!RNumberBox.Value.HasValue) return; if (!GNumberBox.Value.HasValue) return; if (!BNumberBox.Value.HasValue) return; - + var r = numberBox.Name == "RNumberBox" ? GetValueFromNumberBox(numberBox) : (byte) RNumberBox.Value; var g = numberBox.Name == "GNumberBox" ? GetValueFromNumberBox(numberBox) : (byte) GNumberBox.Value; var b = numberBox.Name == "BNumberBox" ? GetValueFromNumberBox(numberBox) : (byte) BNumberBox.Value; - + _ignoreRgbChanges = true; SetColorFromTextBoxes(System.Drawing.Color.FromArgb(r, g, b)); _ignoreRgbChanges = false; } - + /// /// NumberBox provides value only after it has been validated - happens after pressing enter or leaving this control. /// However, we need to get value immediately after the underlying textbox value changes @@ -377,28 +379,28 @@ private void OnRgbNumberBoxTextChanged(object sender, TextChangedEventArgs e) private static byte GetValueFromNumberBox(NumberBox numberBox) { if (!numberBox.Value.HasValue) return byte.MinValue; - + var parsedValue = ParseDouble(numberBox.Text); if (!parsedValue.HasValue) return (byte) numberBox.Value; - + var parsedValueByte = (byte) parsedValue; - + if (parsedValueByte >= numberBox.Minimum && parsedValueByte <= numberBox.Maximum) { return parsedValueByte; } - + // not valid input, return previous value return (byte) numberBox.Value; } - + public static double? ParseDouble(string text) { if (double.TryParse(text, out var result)) { return result; } - + return null; } } \ No newline at end of file diff --git a/source/RevitLookup/Views/Controls/ColorPicker/HSVColor.cs b/source/RevitLookup.UI.Framework/Controls/ColorPicker/HSVColor.cs similarity index 87% rename from source/RevitLookup/Views/Controls/ColorPicker/HSVColor.cs rename to source/RevitLookup.UI.Framework/Controls/ColorPicker/HSVColor.cs index 919607b77..73120b22a 100644 --- a/source/RevitLookup/Views/Controls/ColorPicker/HSVColor.cs +++ b/source/RevitLookup.UI.Framework/Controls/ColorPicker/HSVColor.cs @@ -4,47 +4,47 @@ using Color = System.Windows.Media.Color; -namespace RevitLookup.Views.Controls.ColorPicker; +namespace RevitLookup.UI.Framework.Controls.ColorPicker; public static class HsvColor { public static Color[] GetSpectrum() { var rgbs = new Color[360]; - + for (var h = 0; h < 360; h++) { rgbs[h] = RgbFromHsv(h, 1f, 1f); } - + return rgbs; } - + public static Color[] HueSpectrum(double saturation, double value) { var rgbs = new Color[7]; - + for (var h = 0; h < 7; h++) { rgbs[h] = RgbFromHsv(h * 60, saturation, value); } - + return rgbs; } - + public static Color RgbFromHsv(double h, double s, double v) { if (h > 360 || h < 0 || s > 1 || s < 0 || v > 1 || v < 0) { return Color.FromRgb(0, 0, 0); } - + var c = v * s; var x = c * (1 - Math.Abs(((h / 60) % 2) - 1)); var m = v - c; - + double r = 0, g = 0, b = 0; - + if (h < 60) { r = c; @@ -75,7 +75,7 @@ public static Color RgbFromHsv(double h, double s, double v) r = c; b = x; } - - return Color.FromRgb((byte)((r + m) * 255), (byte)((g + m) * 255), (byte)((b + m) * 255)); + + return Color.FromRgb((byte) ((r + m) * 255), (byte) ((g + m) * 255), (byte) ((b + m) * 255)); } } \ No newline at end of file diff --git a/source/RevitLookup/Views/Controls/ContentPlaceholder/ContentPlaceholder.xaml b/source/RevitLookup.UI.Framework/Controls/ContentPlaceholder/ContentPlaceholder.xaml similarity index 88% rename from source/RevitLookup/Views/Controls/ContentPlaceholder/ContentPlaceholder.xaml rename to source/RevitLookup.UI.Framework/Controls/ContentPlaceholder/ContentPlaceholder.xaml index 0071f76a3..5441956ea 100644 --- a/source/RevitLookup/Views/Controls/ContentPlaceholder/ContentPlaceholder.xaml +++ b/source/RevitLookup.UI.Framework/Controls/ContentPlaceholder/ContentPlaceholder.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:controls="clr-namespace:RevitLookup.Views.Controls" + xmlns:controls="clr-namespace:RevitLookup.UI.Framework.Controls.ContentPlaceholder" mc:Ignorable="d"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/AboutProgram/OpenSourceDialog.xaml.cs b/source/RevitLookup.UI.Framework/Views/AboutProgram/OpenSourceDialog.xaml.cs new file mode 100644 index 000000000..239658300 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/AboutProgram/OpenSourceDialog.xaml.cs @@ -0,0 +1,49 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Documents; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.ViewModels.AboutProgram; +using RevitLookup.Common.Tools; +using Wpf.Ui; + +namespace RevitLookup.UI.Framework.Views.AboutProgram; + +public sealed partial class OpenSourceDialog +{ + public OpenSourceDialog( + IContentDialogService dialogService, + IOpenSourceViewModel viewModel, + IThemeWatcherService themeWatcherService) + : base(dialogService.GetDialogHost()) + { + DataContext = viewModel; + InitializeComponent(); + + themeWatcherService.Watch(this); + } + + private void OpenLink(object sender, RoutedEventArgs args) + { + var link = (Hyperlink) args.OriginalSource; + ProcessTasks.StartShell(link.NavigateUri.OriginalString); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml b/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml new file mode 100644 index 000000000..b18542f28 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml.cs b/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml.cs new file mode 100644 index 000000000..2820d9a77 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Dashboard/DashboardPage.xaml.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.ViewModels.Dashboard; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.UI.Framework.Views.Dashboard; + +public sealed partial class DashboardPage : INavigableView +{ + public DashboardPage(IDashboardViewModel viewModel, IThemeWatcherService themeWatcherService) + { + themeWatcherService.Watch(this); + + ViewModel = viewModel; + DataContext = this; + InitializeComponent(); + } + + public IDashboardViewModel ViewModel { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml b/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml new file mode 100644 index 000000000..5de44190f --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml.cs new file mode 100644 index 000000000..f6bf52e53 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/DecompositionSummaryPage.xaml.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Decomposition; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public sealed partial class DecompositionSummaryPage +{ + public DecompositionSummaryPage( + IServiceProvider serviceProvider, + IDecompositionSummaryViewModel viewModel, + ISettingsService settingsService, + IWindowIntercomService intercomService, + INotificationService notificationService, + IThemeWatcherService themeWatcherService, + ILoggerFactory loggerFactory) + : base(serviceProvider, settingsService, intercomService, notificationService, loggerFactory) + { + themeWatcherService.Watch(this); + + DataContext = this; + ViewModel = viewModel; + InitializeComponent(); + + SearchBoxControl = SummarySearchBox; + TreeViewControl = SummaryTreeView; + DataGridControl = SummaryDataGrid; + InitializeControls(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml b/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml new file mode 100644 index 000000000..fa035df7a --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml.cs new file mode 100644 index 000000000..9911240ce --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/EventsSummaryPage.xaml.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Decomposition; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public sealed partial class EventsSummaryPage +{ + public EventsSummaryPage( + IServiceProvider serviceProvider, + IEventsSummaryViewModel viewModel, + ISettingsService settingsService, + IWindowIntercomService intercomService, + INotificationService notificationService, + IThemeWatcherService themeWatcherService, + ILoggerFactory loggerFactory) + : base(serviceProvider, settingsService, intercomService, notificationService, loggerFactory) + { + themeWatcherService.Watch(this); + + DataContext = this; + ViewModel = viewModel; + InitializeComponent(); + + SearchBoxControl = SummarySearchBox; + TreeViewControl = SummaryTreeView; + DataGridControl = SummaryDataGrid; + InitializeControls(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Compability.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Compability.cs new file mode 100644 index 000000000..3f40a0de1 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Compability.cs @@ -0,0 +1,82 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows; +using RevitLookup.UI.Framework.Utils; +using Wpf.Ui.Controls; +using DataGrid = Wpf.Ui.Controls.DataGrid; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase +{ + private static readonly FieldInfo InternalGridScrollHostField = + typeof(System.Windows.Controls.DataGrid).GetField("_internalScrollHost", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)!; + + private static readonly PropertyInfo InternalGridColumnsProperty = + typeof(System.Windows.Controls.DataGrid).GetProperty("InternalColumns", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)!; + + private static readonly MethodInfo InternalGridInvalidateColumnWidthsComputationMethod = + InternalGridColumnsProperty.PropertyType.GetMethod("InvalidateColumnWidthsComputation", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)!; + + private static readonly MethodInfo InternalGridOnViewportSizeChangedMethod = + typeof(System.Windows.Controls.DataGrid).GetMethod("OnViewportSizeChanged", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)!; + + /// + /// By default, WPF calculates the column width after adding items to the ItemSource. This fix calculates it on loading + /// + /// + /// https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGrid.cs#L98 + /// + private static void FixInitialGridColumnSize(object sender, RoutedEventArgs args) + { + var dataGrid = (DataGrid) sender; + var passiveScrollViewer = dataGrid.FindVisualChild(); + if (passiveScrollViewer is null) + { + dataGrid.ApplyTemplate(); + passiveScrollViewer = dataGrid.FindVisualChild()!; + } + + var gridColumns = InternalGridColumnsProperty.GetValue(dataGrid); + InternalGridScrollHostField.SetValue(dataGrid, passiveScrollViewer); + InternalGridInvalidateColumnWidthsComputationMethod.Invoke(gridColumns, null); + + passiveScrollViewer.SizeChanged += FixCanContentScrollResizing; + } + + /// + /// By default, WPF doesn't recalculate column widths if ScrollViewer.CanContentScroll is enabled + /// + /// + /// https://github.com/dotnet/wpf/blob/main/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/DataGrid.cs#L1961-L1968 + /// + private static void FixCanContentScrollResizing(object sender, SizeChangedEventArgs e) + { + var scrollViewer = (PassiveScrollViewer) sender; + var dataGrid = scrollViewer.FindVisualParent(); //find parent to avoid closure allocations + InternalGridOnViewportSizeChangedMethod.Invoke(dataGrid, [e.PreviousSize, e.NewSize]); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ContextMenu.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ContextMenu.cs new file mode 100644 index 000000000..3f5f33c7a --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ContextMenu.cs @@ -0,0 +1,216 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Utils; +using Wpf.Ui; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase +{ + /// + /// Tree view context menu + /// + private void CreateTreeContextMenu(ObservableDecomposedObject decomposedObject, FrameworkElement row) + { + var contextMenu = new ContextMenu + { + PlacementTarget = row, + Resources = UiApplication.Current.Resources + }; + + row.ContextMenu = contextMenu; + + contextMenu.AddMenuItem("CopyMenuItem") + .SetCommand(decomposedObject, parameter => Clipboard.SetDataObject(parameter.Name)) + .SetShortcut(ModifierKeys.Control, Key.C); + contextMenu.AddMenuItem("HelpMenuItem") + .SetCommand(decomposedObject, parameter => HelpUtils.ShowHelp(parameter.TypeFullName)) + .SetShortcut(Key.F1); + + if (decomposedObject.Descriptor is not IContextMenuConnector connector) return; + + try + { + connector.RegisterMenu(contextMenu, _serviceProvider); + } + catch (Exception exception) + { + _logger.LogError(exception, "Failed to register the context menu"); + _notificationService.ShowError("Failed to register the context menu", exception); + } + } + + /// + /// Data grid row context menu + /// + private void CreateGridRowContextMenu(ObservableDecomposedMember member, FrameworkElement row) + { + var contextMenu = new ContextMenu + { + PlacementTarget = row, + Resources = UiApplication.Current.Resources, + }; + + row.ContextMenu = contextMenu; + + contextMenu.AddMenuItem("CopyMenuItem") + .SetCommand(member, parameter => Clipboard.SetDataObject($"{parameter.Name}: {parameter.Value.Name}")) + .SetShortcut(ModifierKeys.Control, Key.C) + .SetAvailability(member.Value.Name != string.Empty); + + contextMenu.AddMenuItem("CopyMenuItem") + .SetHeader("Copy value") + .SetCommand(member, parameter => Clipboard.SetDataObject(parameter.Value.Name)) + .SetShortcut(ModifierKeys.Control | ModifierKeys.Shift, Key.C) + .SetAvailability(member.Value.Name != string.Empty); + + contextMenu.AddMenuItem("HelpMenuItem") + .SetCommand(member, parameter => HelpUtils.ShowHelp(parameter.DeclaringTypeFullName, parameter.Name)) + .SetShortcut(Key.F1); + + if (member.Value.Descriptor is not IContextMenuConnector connector) return; + + try + { + connector.RegisterMenu(contextMenu, _serviceProvider); + } + catch (Exception exception) + { + _logger.LogError(exception, "Failed to register the context menu"); + _notificationService.ShowError("Failed to register the context menu", exception); + } + } + + /// + /// Data grid context menu + /// + private void CreateGridContextMenu(DataGrid dataGrid) + { + var contextMenu = new ContextMenu + { + PlacementTarget = dataGrid, + Resources = UiApplication.Current.Resources + }; + + dataGrid.ContextMenu = contextMenu; + + contextMenu.AddMenuItem("RefreshMenuItem") + .SetCommand(ViewModel, async parameter => await parameter.RefreshMembersAsync()) + .SetGestureText(Key.F5); + + contextMenu.AddSeparator(); + contextMenu.AddLabel("Columns"); + + contextMenu.AddMenuItem() + .SetHeader("Time") + .SetStaysOpenOnClick(true) + .SetChecked(dataGrid.Columns[2].Visibility == Visibility.Visible) + .SetCommand(dataGrid.Columns[2], parameter => + { + _settingsService.GeneralSettings.ShowTimeColumn = parameter.Visibility != Visibility.Visible; + parameter.Visibility = _settingsService.GeneralSettings.ShowTimeColumn ? Visibility.Visible : Visibility.Collapsed; + }); + + contextMenu.AddMenuItem() + .SetHeader("Memory") + .SetStaysOpenOnClick(true) + .SetChecked(dataGrid.Columns[3].Visibility == Visibility.Visible) + .SetCommand(dataGrid.Columns[3], parameter => + { + _settingsService.GeneralSettings.ShowMemoryColumn = parameter.Visibility != Visibility.Visible; + parameter.Visibility = _settingsService.GeneralSettings.ShowMemoryColumn ? Visibility.Visible : Visibility.Collapsed; + }); + + contextMenu.AddSeparator(); + contextMenu.AddLabel("Show"); + + contextMenu.AddMenuItem() + .SetHeader("Events") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeEvents) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeEvents = !parameter.IncludeEvents; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Extensions") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeExtensions) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeExtensions = !parameter.IncludeExtensions; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Fields") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeFields) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeFields = !parameter.IncludeFields; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Non-public") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludePrivate) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludePrivate = !parameter.IncludePrivate; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Root") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeRootHierarchy) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeRootHierarchy = !parameter.IncludeRootHierarchy; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Static") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeStatic) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeStatic = !parameter.IncludeStatic; + await ViewModel.RefreshMembersAsync(); + }); + contextMenu.AddMenuItem() + .SetHeader("Unsupported") + .SetStaysOpenOnClick(true) + .SetChecked(_settingsService.GeneralSettings.IncludeUnsupported) + .SetCommand(_settingsService.GeneralSettings, async parameter => + { + parameter.IncludeUnsupported = !parameter.IncludeUnsupported; + await ViewModel.RefreshMembersAsync(); + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Gestures.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Gestures.cs new file mode 100644 index 000000000..00dae0eda --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Gestures.cs @@ -0,0 +1,82 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Input; +using RevitLookup.UI.Framework.Views.Windows; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase : INavigationAware +{ + /// + /// Callback when navigating to the current page + /// + public Task OnNavigatedToAsync() + { + var host = _intercomService.GetHost(); + host.PreviewKeyDown += OnPageKeyPressed; + return Task.CompletedTask; + } + + /// + /// Callback when navigating from this page + /// + public Task OnNavigatedFromAsync() + { + var host = _intercomService.GetHost(); + host.PreviewKeyDown -= OnPageKeyPressed; + return Task.CompletedTask; + } + + /// + /// Page shortcuts + /// + private void OnPageKeyPressed(object sender, KeyEventArgs args) + { + AddRefreshShortcut(args); + if (args.Handled) return; + + AddFocusSearchShortcut(sender, args); + } + + private void AddRefreshShortcut(KeyEventArgs args) + { + if (args.Key != Key.F5) return; + + ViewModel.RefreshMembersAsync(); + args.Handled = true; + } + + private void AddFocusSearchShortcut(object sender, KeyEventArgs args) + { + if (SearchBoxControl.IsKeyboardFocused) return; + if (args.KeyboardDevice.Modifiers != ModifierKeys.None) return; + + var rootWindow = (RevitLookupView) sender; + if (rootWindow.RootContentDialog.Content is not null) return; + + if (args.Key is >= Key.D0 and <= Key.Z or >= Key.NumPad0 and <= Key.NumPad9) + { + SearchBoxControl.Focus(); + args.Handled = true; + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Navigation.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Navigation.cs new file mode 100644 index 000000000..fc0f1b2d7 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.Navigation.cs @@ -0,0 +1,134 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.UI.Framework.Utils; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase +{ + /// + /// Handle tree view select event + /// + /// + /// Collect data for selected item + /// + private void OnTreeItemSelected(object sender, RoutedPropertyChangedEventArgs args) + { + switch (args.NewValue) + { + case ObservableDecomposedObject decomposedObject: + ViewModel.SelectedDecomposedObject = decomposedObject; + break; + case ObservableDecomposedObjectsGroup: + ViewModel.SelectedDecomposedObject = null; + break; + default: + return; + } + } + + /// + /// Handle tree view click event + /// + /// + /// Navigate on Ctrl pressed + /// + private void OnTreeItemClicked(object sender, RoutedEventArgs args) + { + if ((Keyboard.Modifiers & ModifierKeys.Control) == 0) return; + args.Handled = true; + + var element = (FrameworkElement) args.OriginalSource; + switch (element.DataContext) + { + case ObservableDecomposedObject item: + ViewModel.Navigate(item); + break; + case ObservableDecomposedObjectsGroup group: + ViewModel.Navigate(group.GroupItems); + break; + } + } + + /// + /// Handle data grid click event + /// + /// + /// Navigate on row clicked + /// + private void OnGridRowClicked(object sender, RoutedEventArgs args) + { + var row = (DataGridRow) sender; + if (row.DataContext is not ObservableDecomposedMember context) return; + + if ((Keyboard.Modifiers & ModifierKeys.Control) == 0) + { + if (context.Value.Descriptor is not IDescriptorCollector) return; + if (context.Value.Descriptor is IDescriptorEnumerator {IsEmpty: true}) return; + } + + ViewModel.Navigate(context.Value); + } + + /// + /// Handle cursor interaction + /// + private static void OnPresenterCursorInteracted(object sender, MouseEventArgs args) + { + var presenter = (FrameworkElement) sender; + if ((Keyboard.Modifiers & ModifierKeys.Control) == 0) + { + presenter.Cursor = null; + return; + } + + FrameworkElement? item = sender switch + { + DataGrid => ((DependencyObject) args.OriginalSource).FindVisualParent(), + TreeView => ((DependencyObject) args.OriginalSource).FindVisualParent(), + _ => throw new NotSupportedException() + }; + + if (item is null) + { + presenter.Cursor = null; + return; + } + + presenter.Cursor = Cursors.Hand; + presenter.PreviewKeyUp += OnPresenterCursorRestored; + } + + /// + /// Restore cursor + /// + private static void OnPresenterCursorRestored(object sender, KeyEventArgs e) + { + var presenter = (FrameworkElement) sender; + presenter.PreviewKeyUp -= OnPresenterCursorRestored; + presenter.Cursor = null; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ToolTips.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ToolTips.cs new file mode 100644 index 000000000..20fbf93c9 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.ToolTips.cs @@ -0,0 +1,114 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Text; +using System.Windows; +using LookupEngine.Abstractions.Enums; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase +{ + /// + /// Create tree view tooltips + /// + private static void CreateTreeTooltip(ObservableDecomposedObject decomposedObject, FrameworkElement row) + { + var builder = new StringBuilder() + .Append("Name: ") + .AppendLine(decomposedObject.Name) + .Append("Type: ") + .AppendLine(decomposedObject.TypeName) + .Append("Full type: ") + .Append(decomposedObject.TypeFullName); + + if (decomposedObject.Description is not null) + { + builder.AppendLine() + .Append("Description: ") + .Append(decomposedObject.Description); + } + + row.ToolTip = builder.ToString(); + } + + /// + /// Create tree view tooltips + /// + private static void CreateTreeTooltip(ObservableDecomposedObjectsGroup decomposedGroup, FrameworkElement row) + { + row.ToolTip = new StringBuilder() + .Append("Type: ") + .AppendLine(decomposedGroup.GroupName) + .Append("Items: ") + .Append(decomposedGroup.GroupItems.Count) + .ToString(); + } + + /// + /// Create data grid tooltips + /// + private static void CreateGridRowTooltip(ObservableDecomposedMember member, FrameworkElement row) + { + var builder = new StringBuilder(); + + if ((member.MemberAttributes & MemberAttributes.Private) != 0) builder.Append("Private "); + if ((member.MemberAttributes & MemberAttributes.Static) != 0) builder.Append("Static "); + if ((member.MemberAttributes & MemberAttributes.Property) != 0) builder.Append("Property: "); + if ((member.MemberAttributes & MemberAttributes.Extension) != 0) builder.Append("Extension: "); + if ((member.MemberAttributes & MemberAttributes.Method) != 0) builder.Append("Method: "); + if ((member.MemberAttributes & MemberAttributes.Event) != 0) builder.Append("Event: "); + if ((member.MemberAttributes & MemberAttributes.Field) != 0) builder.Append("Field: "); + + builder.AppendLine(member.Name) + .Append("Type: ") + .AppendLine(member.Value.TypeName) + .Append("Full type: ") + .AppendLine(member.Value.TypeFullName) + .Append("Value: ") + .Append(member.Value.Name); + + if (member.Value.Description is not null) + { + builder.AppendLine() + .Append("Description: ") + .Append(member.Value.Description); + } + + if (member.ComputationTime > 0) + { + builder.AppendLine() + .Append("Time: ") + .Append(member.ComputationTime) + .Append(" ms"); + } + + if (member.AllocatedBytes > 0) + { + builder.AppendLine() + .Append("Allocated: ") + .Append(member.AllocatedBytes) + .Append(" bytes"); + } + + row.ToolTip = builder.ToString(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.xaml.cs b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.xaml.cs new file mode 100644 index 000000000..5af055132 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Decomposition/SummaryViewBase.xaml.cs @@ -0,0 +1,275 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Utils; +using Wpf.Ui.Abstractions.Controls; +using Wpf.Ui.Controls; +using DataGrid = Wpf.Ui.Controls.DataGrid; +using TreeView = Wpf.Ui.Controls.TreeView; +using TreeViewItem = System.Windows.Controls.TreeViewItem; +using Visibility = System.Windows.Visibility; + +namespace RevitLookup.UI.Framework.Views.Decomposition; + +public partial class SummaryViewBase : Page, INavigableView +{ + private readonly IServiceProvider _serviceProvider; + private readonly ISettingsService _settingsService; + private readonly IWindowIntercomService _intercomService; + private readonly INotificationService _notificationService; + private readonly ILogger _logger; + + protected SummaryViewBase( + IServiceProvider serviceProvider, + ISettingsService settingsService, + IWindowIntercomService intercomService, + INotificationService notificationService, + ILoggerFactory loggerFactory) + { + _serviceProvider = serviceProvider; + _settingsService = settingsService; + _intercomService = intercomService; + _notificationService = notificationService; + _logger = loggerFactory.CreateLogger(); + } + + public required UIElement SearchBoxControl { get; init; } + public required TreeView TreeViewControl { get; init; } + public required DataGrid DataGridControl { get; init; } + public required ISummaryViewModel ViewModel { get; init; } + + protected void InitializeControls() + { + InitializeTreeView(TreeViewControl); + InitializeDataGrid(DataGridControl); + } + + /// + /// Tree view initialization + /// + private void InitializeTreeView(TreeView control) + { + control.SelectedItemChanged += OnTreeItemSelected; + control.ItemsSourceChanged += OnTreeSourceChanged; + control.MouseMove += OnPresenterCursorInteracted; + control.ItemContainerGenerator.StatusChanged += OnTreeViewItemGenerated; + + if (control.ItemsSource is not null) OnTreeSourceChanged(control, control.ItemsSource); + } + + /// + /// Tree view source changed handled. Setup action after the setting source + /// + private static void OnTreeSourceChanged(object? sender, IEnumerable enumerable) + { + var treeView = (TreeView) sender!; + + if (treeView.IsLoaded) + { + ExpandFirstTreeGroup(treeView); + return; + } + + treeView.Loaded += OnLoaded; + return; + + void OnLoaded(object nestedSender, RoutedEventArgs args) + { + var self = (TreeView) nestedSender; + self.Loaded -= OnLoaded; + ExpandFirstTreeGroup(treeView); + } + } + + /// + /// Expand the first tree view group after setting source + /// + /// + private static async void ExpandFirstTreeGroup(TreeView treeView) + { + try + { + // Await Frame transition. GetMembers freezes the thread and breaks the animation + var transitionDuration = (int) NavigationView.TransitionDurationProperty.DefaultMetadata.DefaultValue; + await Task.Delay(transitionDuration); + + //3 is optimal groups count for expanding + if (treeView.Items.Count > 3) return; + + var rootItem = (TreeViewItem?) treeView.GetItemAtIndex(0); + if (rootItem is null) return; + + var nestedItem = (TreeViewItem?) rootItem.GetItemAtIndex(0); + if (nestedItem is null) return; + + nestedItem.IsSelected = true; + } + catch + { + // ignored + } + } + + /// + /// Handle tree view item loaded + /// + /// + /// TreeView item customization after loading + /// + private void OnTreeViewItemGenerated(object? sender, EventArgs _) + { + var generator = (ItemContainerGenerator) sender!; + if (generator.Status == GeneratorStatus.ContainersGenerated) + { + foreach (var item in generator.Items) + { + var treeItem = (ItemsControl) generator.ContainerFromItem(item); + if (treeItem is null) continue; + + treeItem.MouseEnter -= OnTreeItemCaptured; + treeItem.PreviewMouseLeftButtonUp -= OnTreeItemClicked; + + treeItem.MouseEnter += OnTreeItemCaptured; + treeItem.PreviewMouseLeftButtonUp += OnTreeItemClicked; + + if (treeItem.Items.Count > 0) + { + treeItem.ItemContainerGenerator.StatusChanged -= OnTreeViewItemGenerated; + treeItem.ItemContainerGenerator.StatusChanged += OnTreeViewItemGenerated; + } + } + } + } + + /// + /// Create tree view tooltips, menus + /// + private void OnTreeItemCaptured(object? sender, RoutedEventArgs args) + { + var element = (FrameworkElement) sender!; + switch (element.DataContext) + { + case ObservableDecomposedObjectsGroup decomposedGroup: + CreateTreeTooltip(decomposedGroup, element); + break; + case ObservableDecomposedObject decomposedObject: + CreateTreeTooltip(decomposedObject, element); + CreateTreeContextMenu(decomposedObject, element); + break; + } + } + + /// + /// Handle data grid reference changed event + /// + /// + /// Data grid initialization, validation + /// + private void InitializeDataGrid(DataGrid dataGrid) + { + ApplyGrouping(dataGrid); + ValidateTimeColumn(dataGrid); + ValidateAllocatedColumn(dataGrid); + CreateGridContextMenu(dataGrid); + dataGrid.LoadingRow += OnGridRowLoading; + dataGrid.MouseMove += OnPresenterCursorInteracted; + dataGrid.ItemsSourceChanged += ApplySorting; + dataGrid.Loaded += FixInitialGridColumnSize; + } + + /// + /// Set DataGrid grouping rules + /// + private void ApplyGrouping(DataGrid dataGrid) + { + dataGrid.Items.GroupDescriptions!.Clear(); + dataGrid.Items.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ObservableDecomposedMember.DeclaringTypeName))); + } + + /// + /// Set DataGrid sorting rules + /// + private static void ApplySorting(object? sender, EventArgs eventArgs) + { + var dataGrid = (DataGrid) sender!; + + dataGrid.Items.SortDescriptions.Add(new SortDescription(nameof(ObservableDecomposedMember.Depth), ListSortDirection.Descending)); + dataGrid.Items.SortDescriptions.Add(new SortDescription(nameof(ObservableDecomposedMember.MemberAttributes), ListSortDirection.Ascending)); + dataGrid.Items.SortDescriptions.Add(new SortDescription(nameof(ObservableDecomposedMember.Name), ListSortDirection.Ascending)); + } + + // + // Handle data grid row loading event + // + // + // Select row style + // + private void OnGridRowLoading(object? sender, DataGridRowEventArgs args) + { + var row = args.Row; + + row.MouseEnter -= OnGridRowCaptured; + row.PreviewMouseLeftButtonUp -= OnGridRowClicked; + + row.MouseEnter += OnGridRowCaptured; + row.PreviewMouseLeftButtonUp += OnGridRowClicked; + } + + /// + /// Handle data grid row loaded event + /// + /// + /// Create tooltips, context menu + /// + private void OnGridRowCaptured(object sender, RoutedEventArgs args) + { + var element = (FrameworkElement) sender; + var member = (ObservableDecomposedMember) element.DataContext; + CreateGridRowTooltip(member, element); + CreateGridRowContextMenu(member, element); + } + + /// + /// Show/hide time column + /// + private void ValidateTimeColumn(DataGrid control) + { + control.Columns[2].Visibility = _settingsService.GeneralSettings.ShowTimeColumn ? Visibility.Visible : Visibility.Collapsed; + } + + /// + /// Show/hide allocated column + /// + private void ValidateAllocatedColumn(DataGrid control) + { + control.Columns[3].Visibility = _settingsService.GeneralSettings.ShowMemoryColumn ? Visibility.Visible : Visibility.Collapsed; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/EditDialogs/EditIniEntryDialog.xaml b/source/RevitLookup.UI.Framework/Views/EditDialogs/EditIniEntryDialog.xaml new file mode 100644 index 000000000..9993451de --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/EditDialogs/EditIniEntryDialog.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Tools/RevitSettingsPage.xaml.cs b/source/RevitLookup.UI.Framework/Views/Tools/RevitSettingsPage.xaml.cs new file mode 100644 index 000000000..41b85b27a --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Tools/RevitSettingsPage.xaml.cs @@ -0,0 +1,115 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using RevitLookup.Abstractions.ObservableModels.Entries; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Tools; +using Wpf.Ui; +using Wpf.Ui.Controls; +using Wpf.Ui.Extensions; + +namespace RevitLookup.UI.Framework.Views.Tools; + +public sealed partial class RevitSettingsPage +{ + private readonly INotificationService _notificationService; + + public RevitSettingsPage( + IRevitSettingsViewModel viewModel, + IContentDialogService dialogService, + INavigationService navigationService, + IThemeWatcherService themeWatcherService, + INotificationService notificationService) + { + _notificationService = notificationService; + + ViewModel = viewModel; + DataContext = this; + + InitializeComponent(); + ApplyGrouping(); + themeWatcherService.Watch(this); + + if (viewModel.Entries.Count == 0) + { + ShowWarningDialog(dialogService, navigationService); + } + } + + private void ApplyGrouping() + { + EntriesList.Items.GroupDescriptions!.Clear(); + EntriesList.Items.GroupDescriptions.Add(new PropertyGroupDescription(nameof(ObservableIniEntry.Category))); + } + + public IRevitSettingsViewModel ViewModel { get; } + + private async void ShowWarningDialog(IContentDialogService dialogService, INavigationService navigationService) + { + try + { + var options = new SimpleContentDialogCreateOptions + { + Title = "Proceed with caution", + Content = "Changing advanced configuration preferences can impact Revit performance or security", + PrimaryButtonText = "Accept the Risk and Continue", + CloseButtonText = "Quit" + }; + + var result = await dialogService.ShowSimpleDialogAsync(options); + if (result != ContentDialogResult.Primary) + { + navigationService.GoBack(); + } + else + { + await ViewModel.InitializeAsync(); + } + } + catch (Exception exception) + { + _notificationService.ShowError("Initialization error", exception.Message); + } + } + + private async void OnEntryClicked(object sender, MouseButtonEventArgs args) + { + try + { + if (args.OriginalSource is ButtonBase) return; + + await ViewModel.UpdateEntryAsync(); + } + catch (Exception exception) + { + _notificationService.ShowError("Entry updating error", exception.Message); + } + } + + private void OnFilterClicked(object sender, RoutedEventArgs args) + { + FilterFlyout.IsOpen = !FilterFlyout.IsOpen; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Tools/SearchElementsDialog.xaml b/source/RevitLookup.UI.Framework/Views/Tools/SearchElementsDialog.xaml new file mode 100644 index 000000000..659099752 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Tools/SearchElementsDialog.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Tools/UnitsDialog.xaml.cs b/source/RevitLookup.UI.Framework/Views/Tools/UnitsDialog.xaml.cs new file mode 100644 index 000000000..99140d8ad --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Tools/UnitsDialog.xaml.cs @@ -0,0 +1,129 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using RevitLookup.Abstractions.Models.Tools; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.ViewModels.Tools; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Decomposition; +using Wpf.Ui; +using Visibility = System.Windows.Visibility; + +namespace RevitLookup.UI.Framework.Views.Tools; + +public sealed partial class UnitsDialog +{ + private readonly IUnitsViewModel _viewModel; + private readonly INavigationService _navigationService; + + public UnitsDialog( + IContentDialogService dialogService, + IUnitsViewModel viewModel, + INavigationService navigationService, + IThemeWatcherService themeWatcherService) + : base(dialogService.GetDialogHost()) + { + _viewModel = viewModel; + _navigationService = navigationService; + + DataContext = _viewModel; + InitializeComponent(); + + themeWatcherService.Watch(this); + } + + public async Task ShowParametersDialogAsync() + { + _viewModel.InitializeParameters(); + + Title = "BuiltIn Parameters"; + DialogMaxWidth = 1000; + + await ShowAsync(); + } + + public async Task ShowCategoriesDialogAsync() + { + _viewModel.InitializeCategories(); + + Title = "BuiltIn Categories"; + DialogMaxWidth = 600; + + await ShowAsync(); + } + + public async Task ShowForgeSchemaDialogAsync() + { + _viewModel.InitializeForgeSchema(); + + ClassColumn.Visibility = Visibility.Visible; + Title = "Forge Schema"; + DialogMaxWidth = 1100; + + await ShowAsync(); + } + + private void OnMouseEnter(object sender, RoutedEventArgs routedEventArgs) + { + var element = (FrameworkElement) sender; + var unitInfo = (UnitInfo) element.DataContext; + CreateTreeContextMenu(unitInfo, element); + } + + private void CreateTreeContextMenu(UnitInfo info, FrameworkElement row) + { + var contextMenu = new ContextMenu + { + Resources = UiApplication.Current.Resources, + PlacementTarget = row + }; + + contextMenu.AddMenuItem("CopyMenuItem") + .SetHeader("Copy unit") + .SetCommand(info, unitInfo => Clipboard.SetDataObject(unitInfo.Unit)) + .SetShortcut(ModifierKeys.Control, Key.C); + + contextMenu.AddMenuItem("CopyMenuItem") + .SetHeader("Copy label") + .SetCommand(info, unitInfo => Clipboard.SetDataObject(unitInfo.Label)); + + if (info.Class is not null) + { + contextMenu.AddMenuItem("CopyMenuItem") + .SetHeader("Copy class") + .SetCommand(info, unitInfo => Clipboard.SetDataObject(unitInfo.Class!)) + .SetShortcut(ModifierKeys.Control | ModifierKeys.Shift, Key.C); + } + + contextMenu.AddMenuItem("SnoopMenuItem") + .SetHeader("Snoop") + .SetCommand(info, async unitInfo => + { + Hide(); + await _viewModel.DecomposeAsync(unitInfo); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + }); + + row.ContextMenu = contextMenu; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Framework/Views/Visualization/BoundingBoxVisualizationDialog.xaml b/source/RevitLookup.UI.Framework/Views/Visualization/BoundingBoxVisualizationDialog.xaml new file mode 100644 index 000000000..53a454e06 --- /dev/null +++ b/source/RevitLookup.UI.Framework/Views/Visualization/BoundingBoxVisualizationDialog.xaml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Controls/ControlExample.xaml.cs b/source/RevitLookup.UI.Playground/Client/Controls/ControlExample.xaml.cs new file mode 100644 index 000000000..84ae5f3b2 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Controls/ControlExample.xaml.cs @@ -0,0 +1,174 @@ +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows; +using System.Windows.Automation; +using System.Windows.Automation.Peers; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Markup; + +namespace RevitLookup.UI.Playground.Client.Controls; + +/// +/// A control that displays an example of a control +/// +[ContentProperty(nameof(ExampleContent))] +public sealed class ControlExample : Control +{ + static ControlExample() + { + CommandManager.RegisterClassCommandBinding(typeof(ControlExample), new CommandBinding(ApplicationCommands.Copy, Copy_SourceCode)); + } + + public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register( + nameof(HeaderText), + typeof(string), + typeof(ControlExample), + new PropertyMetadata(null) + ); + + public static readonly DependencyProperty ExampleContentProperty = DependencyProperty.Register( + nameof(ExampleContent), + typeof(object), + typeof(ControlExample), + new PropertyMetadata(null) + ); + + public static readonly DependencyProperty XamlCodeProperty = DependencyProperty.Register( + nameof(XamlCode), + typeof(string), + typeof(ControlExample), + new PropertyMetadata(null) + ); + + public static readonly DependencyProperty XamlCodeSourceProperty = DependencyProperty.Register( + nameof(XamlCodeSource), + typeof(Uri), + typeof(ControlExample), + new PropertyMetadata( + null, + static (o, args) => ((ControlExample) o).OnXamlCodeSourceChanged((Uri) args.NewValue) + ) + ); + + public static readonly DependencyProperty CsharpCodeProperty = DependencyProperty.Register( + nameof(CsharpCode), + typeof(string), + typeof(ControlExample), + new PropertyMetadata(null) + ); + + public static readonly DependencyProperty CsharpCodeSourceProperty = DependencyProperty.Register( + nameof(CsharpCodeSource), + typeof(Uri), + typeof(ControlExample), + new PropertyMetadata( + null, + static (o, args) => ((ControlExample) o).OnCsharpCodeSourceChanged((Uri) args.NewValue) + ) + ); + + public string? HeaderText + { + get => (string) GetValue(HeaderTextProperty); + set => SetValue(HeaderTextProperty, value); + } + + public object? ExampleContent + { + get => GetValue(ExampleContentProperty); + set => SetValue(ExampleContentProperty, value); + } + + public string? XamlCode + { + get => (string) GetValue(XamlCodeProperty); + set => SetValue(XamlCodeProperty, value); + } + + public Uri? XamlCodeSource + { + get => (Uri) GetValue(XamlCodeSourceProperty); + set => SetValue(XamlCodeSourceProperty, value); + } + + public string? CsharpCode + { + get => (string) GetValue(CsharpCodeProperty); + set => SetValue(CsharpCodeProperty, value); + } + + public Uri? CsharpCodeSource + { + get => (Uri) GetValue(CsharpCodeSourceProperty); + set => SetValue(CsharpCodeSourceProperty, value); + } + + private void OnXamlCodeSourceChanged(Uri uri) + { + XamlCode = LoadResource(uri); + } + + private void OnCsharpCodeSourceChanged(Uri uri) + { + CsharpCode = LoadResource(uri); + } + + private static void Copy_SourceCode(object sender, RoutedEventArgs e) + { + var controlExample = (ControlExample) sender; + + try + { + switch (((ExecutedRoutedEventArgs) e).Parameter.ToString()) + { + case "Copy_XamlCode": + if (string.IsNullOrEmpty(controlExample.XamlCode)) break; + + Clipboard.SetText(controlExample.XamlCode); + var peer = UIElementAutomationPeer.CreatePeerForElement((Button) e.OriginalSource); +#if NETCOREAPP + peer.RaiseNotificationEvent( + AutomationNotificationKind.Other, + AutomationNotificationProcessing.ImportantMostRecent, + "Source Code Copied", + "ButtonClickedActivity" + ); +#endif + + break; + case "Copy_CsharpCode": + if (string.IsNullOrEmpty(controlExample.CsharpCode)) break; + + Clipboard.SetText(controlExample.CsharpCode); + break; + default: + throw new InvalidOperationException(); + } + } + catch + { + // ignored + } + } + + private static string LoadResource(Uri uri) + { + try + { + if (Application.GetResourceStream(uri) is not { } steamInfo) + { + return string.Empty; + } + + using StreamReader streamReader = new(steamInfo.Stream, Encoding.UTF8); + return streamReader.ReadToEnd(); + } + catch (Exception exception) + { + Debug.WriteLine(exception); + return exception.ToString(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml b/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml new file mode 100644 index 000000000..a23cad965 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml.cs b/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml.cs new file mode 100644 index 000000000..8e67a5b7a --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Controls/PageViewer.xaml.cs @@ -0,0 +1,67 @@ +using System.Windows; +using System.Windows.Automation.Peers; +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Controls.Automation; +using Wpf.Ui; + +namespace RevitLookup.UI.Playground.Client.Controls; + +public sealed partial class PageViewer +{ + private readonly IServiceProvider _serviceProvider; + + public PageViewer( + IServiceProvider serviceProvider, + ISnackbarService snackbarService, + IContentDialogService dialogService, + IWindowIntercomService intercomService) + { + _serviceProvider = serviceProvider; + InitializeComponent(); + + intercomService.SetHost(this); + dialogService.SetDialogHost(RootContentDialog); + snackbarService.SetSnackbarPresenter(RootSnackbar); + } + + public bool? ShowPage() where T : Page + { + var page = _serviceProvider.GetRequiredService(); + Viewer.Navigate(page); + + if (WindowStartupLocation == WindowStartupLocation.CenterScreen) Viewer.SizeChanged += OnViewerFrameResized; + return ShowDialog(); + } + + public void RunService(Action handler) where T : class + { + var service = _serviceProvider.GetRequiredService(); + handler.Invoke(service); + } + + private void OnViewerFrameResized(object sender, SizeChangedEventArgs args) + { + if (args.PreviousSize.Height == 0 || args.PreviousSize.Width == 0) return; + + var self = (Frame) sender; + self.SizeChanged -= OnViewerFrameResized; + + //Move the owner to the screen center after navigation + if (SizeToContent is SizeToContent.WidthAndHeight or SizeToContent.Width) + { + Left -= (ActualWidth - MinWidth) / 2; + } + + if (SizeToContent is SizeToContent.WidthAndHeight or SizeToContent.Height) + { + Top -= (ActualHeight - MinHeight) / 2; + } + } + + protected override AutomationPeer OnCreateAutomationPeer() + { + return new NoAutomationWindowPeer(this); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Helpers/NullToVisibilityConverter.cs b/source/RevitLookup.UI.Playground/Client/Helpers/NullToVisibilityConverter.cs new file mode 100644 index 000000000..6d3e485bb --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Helpers/NullToVisibilityConverter.cs @@ -0,0 +1,27 @@ +using System.Globalization; +using System.Windows; +using System.Windows.Data; +using System.Windows.Markup; + +namespace RevitLookup.UI.Playground.Client.Helpers; + +/// +/// Converts a null value to Visibility.Collapsed +/// +internal sealed class NullToVisibilityConverter : MarkupExtension, IValueConverter +{ + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value is null ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + + public override object? ProvideValue(IServiceProvider serviceProvider) + { + return this; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Helpers/SymbolIconXamlConverter.cs b/source/RevitLookup.UI.Playground/Client/Helpers/SymbolIconXamlConverter.cs new file mode 100644 index 000000000..92933f1f9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Helpers/SymbolIconXamlConverter.cs @@ -0,0 +1,43 @@ +using System.Globalization; +using System.Text; +using System.Windows.Data; +using System.Windows.Markup; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Client.Helpers; + +public sealed class SymbolIconXamlConverter : MarkupExtension, IMultiValueConverter +{ + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values[0] is string text) return text; + + var icon = (SymbolRegular) values[0]; + var filled = (bool) values[1]; + + var builder = new StringBuilder(); + builder.Append(""); + + return builder.ToString(); + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Models/FontIconData.cs b/source/RevitLookup.UI.Playground/Client/Models/FontIconData.cs new file mode 100644 index 000000000..edf024eed --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Models/FontIconData.cs @@ -0,0 +1,15 @@ +namespace RevitLookup.UI.Playground.Client.Models; + +/// +/// IconData class for icons in icon page +/// +[Serializable] +public class FontIconData +{ + public required string Name { get; set; } + public required string Code { get; set; } + + public string Character => char.ConvertFromUtf32(Convert.ToInt32(Code, 16)); + public string CodeGlyph => "\\x" + Code; + public string TextGlyph => "&#x" + Code + ";"; +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Models/FontIcons.json b/source/RevitLookup.UI.Playground/Client/Models/FontIcons.json new file mode 100644 index 000000000..f234337b2 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Models/FontIcons.json @@ -0,0 +1,5614 @@ +[ + { + "Code": "E700", + "Name": "GlobalNavButton" + }, + { + "Code": "E701", + "Name": "Wifi" + }, + { + "Code": "E702", + "Name": "Bluetooth" + }, + { + "Code": "E703", + "Name": "Connect" + }, + { + "Code": "E704", + "Name": "InternetSharing" + }, + { + "Code": "E705", + "Name": "VPN" + }, + { + "Code": "E706", + "Name": "Brightness" + }, + { + "Code": "E707", + "Name": "MapPin" + }, + { + "Code": "E708", + "Name": "QuietHours" + }, + { + "Code": "E709", + "Name": "Airplane" + }, + { + "Code": "E70A", + "Name": "Tablet" + }, + { + "Code": "E70B", + "Name": "QuickNote" + }, + { + "Code": "E70C", + "Name": "RememberedDevice" + }, + { + "Code": "E70D", + "Name": "ChevronDown" + }, + { + "Code": "E70E", + "Name": "ChevronUp" + }, + { + "Code": "E70F", + "Name": "Edit" + }, + { + "Code": "E710", + "Name": "Add" + }, + { + "Code": "E711", + "Name": "Cancel" + }, + { + "Code": "E712", + "Name": "More" + }, + { + "Code": "E713", + "Name": "Settings" + }, + { + "Code": "E714", + "Name": "Video" + }, + { + "Code": "E715", + "Name": "Mail" + }, + { + "Code": "E716", + "Name": "People" + }, + { + "Code": "E717", + "Name": "Phone" + }, + { + "Code": "E718", + "Name": "Pin" + }, + { + "Code": "E719", + "Name": "Shop" + }, + { + "Code": "E71A", + "Name": "Stop" + }, + { + "Code": "E71B", + "Name": "Link" + }, + { + "Code": "E71C", + "Name": "Filter" + }, + { + "Code": "E71D", + "Name": "AllApps" + }, + { + "Code": "E71E", + "Name": "Zoom" + }, + { + "Code": "E71F", + "Name": "ZoomOut" + }, + { + "Code": "E720", + "Name": "Microphone" + }, + { + "Code": "E721", + "Name": "Search" + }, + { + "Code": "E722", + "Name": "Camera" + }, + { + "Code": "E723", + "Name": "Attach" + }, + { + "Code": "E724", + "Name": "Send" + }, + { + "Code": "E725", + "Name": "SendFill" + }, + { + "Code": "E726", + "Name": "WalkSolid" + }, + { + "Code": "E727", + "Name": "InPrivate" + }, + { + "Code": "E728", + "Name": "FavoriteList" + }, + { + "Code": "E729", + "Name": "PageSolid" + }, + { + "Code": "E72A", + "Name": "Forward" + }, + { + "Code": "E72B", + "Name": "Back" + }, + { + "Code": "E72C", + "Name": "Refresh" + }, + { + "Code": "E72D", + "Name": "Share" + }, + { + "Code": "E72E", + "Name": "Lock" + }, + { + "Code": "E730", + "Name": "ReportHacked" + }, + { + "Code": "E731", + "Name": "EMI" + }, + { + "Code": "E734", + "Name": "FavoriteStar" + }, + { + "Code": "E735", + "Name": "FavoriteStarFill" + }, + { + "Code": "E736", + "Name": "ReadingMode" + }, + { + "Code": "E737", + "Name": "Favicon" + }, + { + "Code": "E738", + "Name": "Remove" + }, + { + "Code": "E739", + "Name": "Checkbox" + }, + { + "Code": "E73A", + "Name": "CheckboxComposite" + }, + { + "Code": "E73B", + "Name": "CheckboxFill" + }, + { + "Code": "E73C", + "Name": "CheckboxIndeterminate" + }, + { + "Code": "E73D", + "Name": "CheckboxCompositeReversed" + }, + { + "Code": "E73E", + "Name": "CheckMark" + }, + { + "Code": "E73F", + "Name": "BackToWindow" + }, + { + "Code": "E740", + "Name": "FullScreen" + }, + { + "Code": "E741", + "Name": "ResizeTouchLarger" + }, + { + "Code": "E742", + "Name": "ResizeTouchSmaller" + }, + { + "Code": "E743", + "Name": "ResizeMouseSmall" + }, + { + "Code": "E744", + "Name": "ResizeMouseMedium" + }, + { + "Code": "E745", + "Name": "ResizeMouseWide" + }, + { + "Code": "E746", + "Name": "ResizeMouseTall" + }, + { + "Code": "E747", + "Name": "ResizeMouseLarge" + }, + { + "Code": "E748", + "Name": "SwitchUser" + }, + { + "Code": "E749", + "Name": "Print" + }, + { + "Code": "E74A", + "Name": "Up" + }, + { + "Code": "E74B", + "Name": "Down" + }, + { + "Code": "E74C", + "Name": "OEM" + }, + { + "Code": "E74D", + "Name": "Delete" + }, + { + "Code": "E74E", + "Name": "Save" + }, + { + "Code": "E74F", + "Name": "Mute" + }, + { + "Code": "E750", + "Name": "BackSpaceQWERTY" + }, + { + "Code": "E751", + "Name": "ReturnKey" + }, + { + "Code": "E752", + "Name": "UpArrowShiftKey" + }, + { + "Code": "E753", + "Name": "Cloud" + }, + { + "Code": "E754", + "Name": "Flashlight" + }, + { + "Code": "E755", + "Name": "RotationLock" + }, + { + "Code": "E756", + "Name": "CommandPrompt" + }, + { + "Code": "E759", + "Name": "SIPMove" + }, + { + "Code": "E75A", + "Name": "SIPUndock" + }, + { + "Code": "E75B", + "Name": "SIPRedock" + }, + { + "Code": "E75C", + "Name": "EraseTool" + }, + { + "Code": "E75D", + "Name": "UnderscoreSpace" + }, + { + "Code": "E75E", + "Name": "GripperTool" + }, + { + "Code": "E75F", + "Name": "Dialpad" + }, + { + "Code": "E760", + "Name": "PageLeft" + }, + { + "Code": "E761", + "Name": "PageRight" + }, + { + "Code": "E762", + "Name": "MultiSelect" + }, + { + "Code": "E763", + "Name": "KeyboardLeftHanded" + }, + { + "Code": "E764", + "Name": "KeyboardRightHanded" + }, + { + "Code": "E765", + "Name": "KeyboardClassic" + }, + { + "Code": "E766", + "Name": "KeyboardSplit" + }, + { + "Code": "E767", + "Name": "Volume" + }, + { + "Code": "E768", + "Name": "Play" + }, + { + "Code": "E769", + "Name": "Pause" + }, + { + "Code": "E76B", + "Name": "ChevronLeft" + }, + { + "Code": "E76C", + "Name": "ChevronRight" + }, + { + "Code": "E76D", + "Name": "InkingTool" + }, + { + "Code": "E76E", + "Name": "Emoji2" + }, + { + "Code": "E76F", + "Name": "GripperBarHorizontal" + }, + { + "Code": "E770", + "Name": "System" + }, + { + "Code": "E771", + "Name": "Personalize" + }, + { + "Code": "E772", + "Name": "Devices" + }, + { + "Code": "E773", + "Name": "SearchAndApps" + }, + { + "Code": "E774", + "Name": "Globe" + }, + { + "Code": "E775", + "Name": "TimeLanguage" + }, + { + "Code": "E776", + "Name": "EaseOfAccess" + }, + { + "Code": "E777", + "Name": "UpdateRestore" + }, + { + "Code": "E778", + "Name": "HangUp" + }, + { + "Code": "E779", + "Name": "ContactInfo" + }, + { + "Code": "E77A", + "Name": "Unpin" + }, + { + "Code": "E77B", + "Name": "Contact" + }, + { + "Code": "E77C", + "Name": "Memo" + }, + { + "Code": "E77E", + "Name": "IncomingCall" + }, + { + "Code": "E77F", + "Name": "Paste" + }, + { + "Code": "E780", + "Name": "PhoneBook" + }, + { + "Code": "E781", + "Name": "LEDLight" + }, + { + "Code": "E783", + "Name": "Error" + }, + { + "Code": "E784", + "Name": "GripperBarVertical" + }, + { + "Code": "E785", + "Name": "Unlock" + }, + { + "Code": "E786", + "Name": "Slideshow" + }, + { + "Code": "E787", + "Name": "Calendar" + }, + { + "Code": "E788", + "Name": "GripperResize" + }, + { + "Code": "E789", + "Name": "Megaphone" + }, + { + "Code": "E78A", + "Name": "Trim" + }, + { + "Code": "E78B", + "Name": "NewWindow" + }, + { + "Code": "E78C", + "Name": "SaveLocal" + }, + { + "Code": "E790", + "Name": "Color" + }, + { + "Code": "E791", + "Name": "DataSense" + }, + { + "Code": "E792", + "Name": "SaveAs" + }, + { + "Code": "E793", + "Name": "Light" + }, + { + "Code": "E799", + "Name": "AspectRatio" + }, + { + "Code": "E7A5", + "Name": "DataSenseBar" + }, + { + "Code": "E7A6", + "Name": "Redo" + }, + { + "Code": "E7A7", + "Name": "Undo" + }, + { + "Code": "E7A8", + "Name": "Crop" + }, + { + "Code": "E7AC", + "Name": "OpenWith" + }, + { + "Code": "E7AD", + "Name": "Rotate" + }, + { + "Code": "E7B3", + "Name": "RedEye" + }, + { + "Code": "E7B5", + "Name": "SetlockScreen" + }, + { + "Code": "E7B7", + "Name": "MapPin2" + }, + { + "Code": "E7B8", + "Name": "Package" + }, + { + "Code": "E7BA", + "Name": "Warning" + }, + { + "Code": "E7BC", + "Name": "ReadingList" + }, + { + "Code": "E7BE", + "Name": "Education" + }, + { + "Code": "E7BF", + "Name": "ShoppingCart" + }, + { + "Code": "E7C0", + "Name": "Train" + }, + { + "Code": "E7C1", + "Name": "Flag" + }, + { + "Code": "E7C2", + "Name": "Move" + }, + { + "Code": "E7C3", + "Name": "Page" + }, + { + "Code": "E7C4", + "Name": "TaskView" + }, + { + "Code": "E7C5", + "Name": "BrowsePhotos" + }, + { + "Code": "E7C6", + "Name": "HalfStarLeft" + }, + { + "Code": "E7C7", + "Name": "HalfStarRight" + }, + { + "Code": "E7C8", + "Name": "Record" + }, + { + "Code": "E7C9", + "Name": "TouchPointer" + }, + { + "Code": "E7DE", + "Name": "LangJPN" + }, + { + "Code": "E7E3", + "Name": "Ferry" + }, + { + "Code": "E7E6", + "Name": "Highlight" + }, + { + "Code": "E7E7", + "Name": "ActionCenterNotification" + }, + { + "Code": "E7E8", + "Name": "PowerButton" + }, + { + "Code": "E7EA", + "Name": "ResizeTouchNarrower" + }, + { + "Code": "E7EB", + "Name": "ResizeTouchShorter" + }, + { + "Code": "E7EC", + "Name": "DrivingMode" + }, + { + "Code": "E7ED", + "Name": "RingerSilent" + }, + { + "Code": "E7EE", + "Name": "OtherUser" + }, + { + "Code": "E7EF", + "Name": "Admin" + }, + { + "Code": "E7F0", + "Name": "CC" + }, + { + "Code": "E7F1", + "Name": "SDCard" + }, + { + "Code": "E7F2", + "Name": "CallForwarding" + }, + { + "Code": "E7F3", + "Name": "SettingsDisplaySound" + }, + { + "Code": "E7F4", + "Name": "TVMonitor" + }, + { + "Code": "E7F5", + "Name": "Speakers" + }, + { + "Code": "E7F6", + "Name": "Headphone" + }, + { + "Code": "E7F7", + "Name": "DeviceLaptopPic" + }, + { + "Code": "E7F8", + "Name": "DeviceLaptopNoPic" + }, + { + "Code": "E7F9", + "Name": "DeviceMonitorRightPic" + }, + { + "Code": "E7FA", + "Name": "DeviceMonitorLeftPic" + }, + { + "Code": "E7FB", + "Name": "DeviceMonitorNoPic" + }, + { + "Code": "E7FC", + "Name": "Game" + }, + { + "Code": "E7FD", + "Name": "HorizontalTabKey" + }, + { + "Code": "E802", + "Name": "StreetsideSplitMinimize" + }, + { + "Code": "E803", + "Name": "StreetsideSplitExpand" + }, + { + "Code": "E804", + "Name": "Car" + }, + { + "Code": "E805", + "Name": "Walk" + }, + { + "Code": "E806", + "Name": "Bus" + }, + { + "Code": "E809", + "Name": "TiltUp" + }, + { + "Code": "E80A", + "Name": "TiltDown" + }, + { + "Code": "E80B", + "Name": "CallControl" + }, + { + "Code": "E80C", + "Name": "RotateMapRight" + }, + { + "Code": "E80D", + "Name": "RotateMapLeft" + }, + { + "Code": "E80F", + "Name": "Home" + }, + { + "Code": "E811", + "Name": "ParkingLocation" + }, + { + "Code": "E812", + "Name": "MapCompassTop" + }, + { + "Code": "E813", + "Name": "MapCompassBottom" + }, + { + "Code": "E814", + "Name": "IncidentTriangle" + }, + { + "Code": "E815", + "Name": "Touch" + }, + { + "Code": "E816", + "Name": "MapDirections" + }, + { + "Code": "E819", + "Name": "StartPoint" + }, + { + "Code": "E81A", + "Name": "StopPoint" + }, + { + "Code": "E81B", + "Name": "EndPoint" + }, + { + "Code": "E81C", + "Name": "History" + }, + { + "Code": "E81D", + "Name": "Location" + }, + { + "Code": "E81E", + "Name": "MapLayers" + }, + { + "Code": "E81F", + "Name": "Accident" + }, + { + "Code": "E821", + "Name": "Work" + }, + { + "Code": "E822", + "Name": "Construction" + }, + { + "Code": "E823", + "Name": "Recent" + }, + { + "Code": "E825", + "Name": "Bank" + }, + { + "Code": "E826", + "Name": "DownloadMap" + }, + { + "Code": "E829", + "Name": "InkingToolFill2" + }, + { + "Code": "E82A", + "Name": "HighlightFill2" + }, + { + "Code": "E82B", + "Name": "EraseToolFill" + }, + { + "Code": "E82C", + "Name": "EraseToolFill2" + }, + { + "Code": "E82D", + "Name": "Dictionary" + }, + { + "Code": "E82E", + "Name": "DictionaryAdd" + }, + { + "Code": "E82F", + "Name": "ToolTip" + }, + { + "Code": "E830", + "Name": "ChromeBack" + }, + { + "Code": "E835", + "Name": "ProvisioningPackage" + }, + { + "Code": "E836", + "Name": "AddRemoteDevice" + }, + { + "Code": "E838", + "Name": "FolderOpen" + }, + { + "Code": "E839", + "Name": "Ethernet" + }, + { + "Code": "E83A", + "Name": "ShareBroadband" + }, + { + "Code": "E83B", + "Name": "DirectAccess" + }, + { + "Code": "E83C", + "Name": "DialUp" + }, + { + "Code": "E83D", + "Name": "DefenderApp" + }, + { + "Code": "E83E", + "Name": "BatteryCharging9" + }, + { + "Code": "E83F", + "Name": "Battery10" + }, + { + "Code": "E840", + "Name": "Pinned" + }, + { + "Code": "E841", + "Name": "PinFill" + }, + { + "Code": "E842", + "Name": "PinnedFill" + }, + { + "Code": "E843", + "Name": "PeriodKey" + }, + { + "Code": "E844", + "Name": "PuncKey" + }, + { + "Code": "E845", + "Name": "RevToggleKey" + }, + { + "Code": "E846", + "Name": "RightArrowKeyTime1" + }, + { + "Code": "E847", + "Name": "RightArrowKeyTime2" + }, + { + "Code": "E848", + "Name": "LeftQuote" + }, + { + "Code": "E849", + "Name": "RightQuote" + }, + { + "Code": "E84A", + "Name": "DownShiftKey" + }, + { + "Code": "E84B", + "Name": "UpShiftKey" + }, + { + "Code": "E84C", + "Name": "PuncKey0" + }, + { + "Code": "E84D", + "Name": "PuncKeyLeftBottom" + }, + { + "Code": "E84E", + "Name": "RightArrowKeyTime3" + }, + { + "Code": "E84F", + "Name": "RightArrowKeyTime4" + }, + { + "Code": "E850", + "Name": "Battery0" + }, + { + "Code": "E851", + "Name": "Battery1" + }, + { + "Code": "E852", + "Name": "Battery2" + }, + { + "Code": "E853", + "Name": "Battery3" + }, + { + "Code": "E854", + "Name": "Battery4" + }, + { + "Code": "E855", + "Name": "Battery5" + }, + { + "Code": "E856", + "Name": "Battery6" + }, + { + "Code": "E857", + "Name": "Battery7" + }, + { + "Code": "E858", + "Name": "Battery8" + }, + { + "Code": "E859", + "Name": "Battery9" + }, + { + "Code": "E85A", + "Name": "BatteryCharging0" + }, + { + "Code": "E85B", + "Name": "BatteryCharging1" + }, + { + "Code": "E85C", + "Name": "BatteryCharging2" + }, + { + "Code": "E85D", + "Name": "BatteryCharging3" + }, + { + "Code": "E85E", + "Name": "BatteryCharging4" + }, + { + "Code": "E85F", + "Name": "BatteryCharging5" + }, + { + "Code": "E860", + "Name": "BatteryCharging6" + }, + { + "Code": "E861", + "Name": "BatteryCharging7" + }, + { + "Code": "E862", + "Name": "BatteryCharging8" + }, + { + "Code": "E863", + "Name": "BatterySaver0" + }, + { + "Code": "E864", + "Name": "BatterySaver1" + }, + { + "Code": "E865", + "Name": "BatterySaver2" + }, + { + "Code": "E866", + "Name": "BatterySaver3" + }, + { + "Code": "E867", + "Name": "BatterySaver4" + }, + { + "Code": "E868", + "Name": "BatterySaver5" + }, + { + "Code": "E869", + "Name": "BatterySaver6" + }, + { + "Code": "E86A", + "Name": "BatterySaver7" + }, + { + "Code": "E86B", + "Name": "BatterySaver8" + }, + { + "Code": "E86C", + "Name": "SignalBars1" + }, + { + "Code": "E86D", + "Name": "SignalBars2" + }, + { + "Code": "E86E", + "Name": "SignalBars3" + }, + { + "Code": "E86F", + "Name": "SignalBars4" + }, + { + "Code": "E870", + "Name": "SignalBars5" + }, + { + "Code": "E871", + "Name": "SignalNotConnected" + }, + { + "Code": "E872", + "Name": "Wifi1" + }, + { + "Code": "E873", + "Name": "Wifi2" + }, + { + "Code": "E874", + "Name": "Wifi3" + }, + { + "Code": "E875", + "Name": "MobSIMLock" + }, + { + "Code": "E876", + "Name": "MobSIMMissing" + }, + { + "Code": "E877", + "Name": "Vibrate" + }, + { + "Code": "E878", + "Name": "RoamingInternational" + }, + { + "Code": "E879", + "Name": "RoamingDomestic" + }, + { + "Code": "E87A", + "Name": "CallForwardInternational" + }, + { + "Code": "E87B", + "Name": "CallForwardRoaming" + }, + { + "Code": "E87C", + "Name": "JpnRomanji" + }, + { + "Code": "E87D", + "Name": "JpnRomanjiLock" + }, + { + "Code": "E87E", + "Name": "JpnRomanjiShift" + }, + { + "Code": "E87F", + "Name": "JpnRomanjiShiftLock" + }, + { + "Code": "E880", + "Name": "StatusDataTransfer" + }, + { + "Code": "E881", + "Name": "StatusDataTransferVPN" + }, + { + "Code": "E882", + "Name": "StatusDualSIM2" + }, + { + "Code": "E883", + "Name": "StatusDualSIM2VPN" + }, + { + "Code": "E884", + "Name": "StatusDualSIM1" + }, + { + "Code": "E885", + "Name": "StatusDualSIM1VPN" + }, + { + "Code": "E886", + "Name": "StatusSGLTE" + }, + { + "Code": "E887", + "Name": "StatusSGLTECell" + }, + { + "Code": "E888", + "Name": "StatusSGLTEDataVPN" + }, + { + "Code": "E889", + "Name": "StatusVPN" + }, + { + "Code": "E88A", + "Name": "WifiHotspot" + }, + { + "Code": "E88B", + "Name": "LanguageKor" + }, + { + "Code": "E88C", + "Name": "LanguageCht" + }, + { + "Code": "E88D", + "Name": "LanguageChs" + }, + { + "Code": "E88E", + "Name": "USB" + }, + { + "Code": "E88F", + "Name": "InkingToolFill" + }, + { + "Code": "E890", + "Name": "View" + }, + { + "Code": "E891", + "Name": "HighlightFill" + }, + { + "Code": "E892", + "Name": "Previous" + }, + { + "Code": "E893", + "Name": "Next" + }, + { + "Code": "E894", + "Name": "Clear" + }, + { + "Code": "E895", + "Name": "Sync" + }, + { + "Code": "E896", + "Name": "Download" + }, + { + "Code": "E897", + "Name": "Help" + }, + { + "Code": "E898", + "Name": "Upload" + }, + { + "Code": "E899", + "Name": "Emoji" + }, + { + "Code": "E89A", + "Name": "TwoPage" + }, + { + "Code": "E89B", + "Name": "LeaveChat" + }, + { + "Code": "E89C", + "Name": "MailForward" + }, + { + "Code": "E89E", + "Name": "RotateCamera" + }, + { + "Code": "E89F", + "Name": "ClosePane" + }, + { + "Code": "E8A0", + "Name": "OpenPane" + }, + { + "Code": "E8A1", + "Name": "PreviewLink" + }, + { + "Code": "E8A2", + "Name": "AttachCamera" + }, + { + "Code": "E8A3", + "Name": "ZoomIn" + }, + { + "Code": "E8A4", + "Name": "Bookmarks" + }, + { + "Code": "E8A5", + "Name": "Document" + }, + { + "Code": "E8A6", + "Name": "ProtectedDocument" + }, + { + "Code": "E8A7", + "Name": "OpenInNewWindow" + }, + { + "Code": "E8A8", + "Name": "MailFill" + }, + { + "Code": "E8A9", + "Name": "ViewAll" + }, + { + "Code": "E8AA", + "Name": "VideoChat" + }, + { + "Code": "E8AB", + "Name": "Switch" + }, + { + "Code": "E8AC", + "Name": "Rename" + }, + { + "Code": "E8AD", + "Name": "Go" + }, + { + "Code": "E8AE", + "Name": "SurfaceHub" + }, + { + "Code": "E8AF", + "Name": "Remote" + }, + { + "Code": "E8B0", + "Name": "Click" + }, + { + "Code": "E8B1", + "Name": "Shuffle" + }, + { + "Code": "E8B2", + "Name": "Movies" + }, + { + "Code": "E8B3", + "Name": "SelectAll" + }, + { + "Code": "E8B4", + "Name": "Orientation" + }, + { + "Code": "E8B5", + "Name": "Import" + }, + { + "Code": "E8B6", + "Name": "ImportAll" + }, + { + "Code": "E8B7", + "Name": "Folder" + }, + { + "Code": "E8B8", + "Name": "Webcam" + }, + { + "Code": "E8B9", + "Name": "Picture" + }, + { + "Code": "E8BA", + "Name": "Caption" + }, + { + "Code": "E8BB", + "Name": "ChromeClose" + }, + { + "Code": "E8BC", + "Name": "ShowResults" + }, + { + "Code": "E8BD", + "Name": "Message" + }, + { + "Code": "E8BE", + "Name": "Leaf" + }, + { + "Code": "E8BF", + "Name": "CalendarDay" + }, + { + "Code": "E8C0", + "Name": "CalendarWeek" + }, + { + "Code": "E8C1", + "Name": "Characters" + }, + { + "Code": "E8C2", + "Name": "MailReplyAll" + }, + { + "Code": "E8C3", + "Name": "Read" + }, + { + "Code": "E8C4", + "Name": "ShowBcc" + }, + { + "Code": "E8C5", + "Name": "HideBcc" + }, + { + "Code": "E8C6", + "Name": "Cut" + }, + { + "Code": "E8C7", + "Name": "PaymentCard" + }, + { + "Code": "E8C8", + "Name": "Copy" + }, + { + "Code": "E8C9", + "Name": "Important" + }, + { + "Code": "E8CA", + "Name": "MailReply" + }, + { + "Code": "E8CB", + "Name": "Sort" + }, + { + "Code": "E8CC", + "Name": "MobileTablet" + }, + { + "Code": "E8CD", + "Name": "DisconnectDrive" + }, + { + "Code": "E8CE", + "Name": "MapDrive" + }, + { + "Code": "E8CF", + "Name": "ContactPresence" + }, + { + "Code": "E8D0", + "Name": "Priority" + }, + { + "Code": "E8D1", + "Name": "GotoToday" + }, + { + "Code": "E8D2", + "Name": "Font" + }, + { + "Code": "E8D3", + "Name": "FontColor" + }, + { + "Code": "E8D4", + "Name": "Contact2" + }, + { + "Code": "E8D5", + "Name": "FolderFill" + }, + { + "Code": "E8D6", + "Name": "Audio" + }, + { + "Code": "E8D7", + "Name": "Permissions" + }, + { + "Code": "E8D8", + "Name": "DisableUpdates" + }, + { + "Code": "E8D9", + "Name": "Unfavorite" + }, + { + "Code": "E8DA", + "Name": "OpenLocal" + }, + { + "Code": "E8DB", + "Name": "Italic" + }, + { + "Code": "E8DC", + "Name": "Underline" + }, + { + "Code": "E8DD", + "Name": "Bold" + }, + { + "Code": "E8DE", + "Name": "MoveToFolder" + }, + { + "Code": "E8DF", + "Name": "LikeDislike" + }, + { + "Code": "E8E0", + "Name": "Dislike" + }, + { + "Code": "E8E1", + "Name": "Like" + }, + { + "Code": "E8E2", + "Name": "AlignRight" + }, + { + "Code": "E8E3", + "Name": "AlignCenter" + }, + { + "Code": "E8E4", + "Name": "AlignLeft" + }, + { + "Code": "E8E5", + "Name": "OpenFile" + }, + { + "Code": "E8E6", + "Name": "ClearSelection" + }, + { + "Code": "E8E7", + "Name": "FontDecrease" + }, + { + "Code": "E8E8", + "Name": "FontIncrease" + }, + { + "Code": "E8E9", + "Name": "FontSize" + }, + { + "Code": "E8EA", + "Name": "CellPhone" + }, + { + "Code": "E8EB", + "Name": "Reshare" + }, + { + "Code": "E8EC", + "Name": "Tag" + }, + { + "Code": "E8ED", + "Name": "RepeatOne" + }, + { + "Code": "E8EE", + "Name": "RepeatAll" + }, + { + "Code": "E8EF", + "Name": "Calculator" + }, + { + "Code": "E8F0", + "Name": "Directions" + }, + { + "Code": "E8F1", + "Name": "Library" + }, + { + "Code": "E8F2", + "Name": "ChatBubbles" + }, + { + "Code": "E8F3", + "Name": "PostUpdate" + }, + { + "Code": "E8F4", + "Name": "NewFolder" + }, + { + "Code": "E8F5", + "Name": "CalendarReply" + }, + { + "Code": "E8F6", + "Name": "UnsyncFolder" + }, + { + "Code": "E8F7", + "Name": "SyncFolder" + }, + { + "Code": "E8F8", + "Name": "BlockContact" + }, + { + "Code": "E8F9", + "Name": "SwitchApps" + }, + { + "Code": "E8FA", + "Name": "AddFriend" + }, + { + "Code": "E8FB", + "Name": "Accept" + }, + { + "Code": "E8FC", + "Name": "GoToStart" + }, + { + "Code": "E8FD", + "Name": "BulletedList" + }, + { + "Code": "E8FE", + "Name": "Scan" + }, + { + "Code": "E8FF", + "Name": "Preview" + }, + { + "Code": "E902", + "Name": "Group" + }, + { + "Code": "E904", + "Name": "ZeroBars" + }, + { + "Code": "E905", + "Name": "OneBar" + }, + { + "Code": "E906", + "Name": "TwoBars" + }, + { + "Code": "E907", + "Name": "ThreeBars" + }, + { + "Code": "E908", + "Name": "FourBars" + }, + { + "Code": "E909", + "Name": "World" + }, + { + "Code": "E90A", + "Name": "Comment" + }, + { + "Code": "E90B", + "Name": "MusicInfo" + }, + { + "Code": "E90C", + "Name": "DockLeft" + }, + { + "Code": "E90D", + "Name": "DockRight" + }, + { + "Code": "E90E", + "Name": "DockBottom" + }, + { + "Code": "E90F", + "Name": "Repair" + }, + { + "Code": "E910", + "Name": "Accounts" + }, + { + "Code": "E911", + "Name": "DullSound" + }, + { + "Code": "E912", + "Name": "Manage" + }, + { + "Code": "E913", + "Name": "Street" + }, + { + "Code": "E914", + "Name": "Printer3D" + }, + { + "Code": "E915", + "Name": "RadioBullet" + }, + { + "Code": "E916", + "Name": "Stopwatch" + }, + { + "Code": "E91B", + "Name": "Photo" + }, + { + "Code": "E91C", + "Name": "ActionCenter" + }, + { + "Code": "E91F", + "Name": "FullCircleMask" + }, + { + "Code": "E921", + "Name": "ChromeMinimize" + }, + { + "Code": "E922", + "Name": "ChromeMaximize" + }, + { + "Code": "E923", + "Name": "ChromeRestore" + }, + { + "Code": "E924", + "Name": "Annotation" + }, + { + "Code": "E925", + "Name": "BackSpaceQWERTYSm" + }, + { + "Code": "E926", + "Name": "BackSpaceQWERTYMd" + }, + { + "Code": "E927", + "Name": "Swipe" + }, + { + "Code": "E928", + "Name": "Fingerprint" + }, + { + "Code": "E929", + "Name": "Handwriting" + }, + { + "Code": "E92C", + "Name": "ChromeBackToWindow" + }, + { + "Code": "E92D", + "Name": "ChromeFullScreen" + }, + { + "Code": "E92E", + "Name": "KeyboardStandard" + }, + { + "Code": "E92F", + "Name": "KeyboardDismiss" + }, + { + "Code": "E930", + "Name": "Completed" + }, + { + "Code": "E931", + "Name": "ChromeAnnotate" + }, + { + "Code": "E932", + "Name": "Label" + }, + { + "Code": "E933", + "Name": "IBeam" + }, + { + "Code": "E934", + "Name": "IBeamOutline" + }, + { + "Code": "E935", + "Name": "FlickDown" + }, + { + "Code": "E936", + "Name": "FlickUp" + }, + { + "Code": "E937", + "Name": "FlickLeft" + }, + { + "Code": "E938", + "Name": "FlickRight" + }, + { + "Code": "E939", + "Name": "FeedbackApp" + }, + { + "Code": "E93C", + "Name": "MusicAlbum" + }, + { + "Code": "E93E", + "Name": "Streaming" + }, + { + "Code": "E943", + "Name": "Code" + }, + { + "Code": "E944", + "Name": "ReturnToWindow" + }, + { + "Code": "E945", + "Name": "LightningBolt" + }, + { + "Code": "E946", + "Name": "Info" + }, + { + "Code": "E947", + "Name": "CalculatorMultiply" + }, + { + "Code": "E948", + "Name": "CalculatorAddition" + }, + { + "Code": "E949", + "Name": "CalculatorSubtract" + }, + { + "Code": "E94A", + "Name": "CalculatorDivide" + }, + { + "Code": "E94B", + "Name": "CalculatorSquareroot" + }, + { + "Code": "E94C", + "Name": "CalculatorPercentage" + }, + { + "Code": "E94D", + "Name": "CalculatorNegate" + }, + { + "Code": "E94E", + "Name": "CalculatorEqualTo" + }, + { + "Code": "E94F", + "Name": "CalculatorBackspace" + }, + { + "Code": "E950", + "Name": "Component" + }, + { + "Code": "E951", + "Name": "DMC" + }, + { + "Code": "E952", + "Name": "Dock" + }, + { + "Code": "E953", + "Name": "MultimediaDMS" + }, + { + "Code": "E954", + "Name": "MultimediaDVR" + }, + { + "Code": "E955", + "Name": "MultimediaPMP" + }, + { + "Code": "E956", + "Name": "PrintfaxPrinterFile" + }, + { + "Code": "E957", + "Name": "Sensor" + }, + { + "Code": "E958", + "Name": "StorageOptical" + }, + { + "Code": "E95A", + "Name": "Communications" + }, + { + "Code": "E95B", + "Name": "Headset" + }, + { + "Code": "E95D", + "Name": "Projector" + }, + { + "Code": "E95E", + "Name": "Health" + }, + { + "Code": "E95F", + "Name": "Wire" + }, + { + "Code": "E960", + "Name": "Webcam2" + }, + { + "Code": "E961", + "Name": "Input" + }, + { + "Code": "E962", + "Name": "Mouse" + }, + { + "Code": "E963", + "Name": "Smartcard" + }, + { + "Code": "E964", + "Name": "SmartcardVirtual" + }, + { + "Code": "E965", + "Name": "MediaStorageTower" + }, + { + "Code": "E966", + "Name": "ReturnKeySm" + }, + { + "Code": "E967", + "Name": "GameConsole" + }, + { + "Code": "E968", + "Name": "Network" + }, + { + "Code": "E969", + "Name": "StorageNetworkWireless" + }, + { + "Code": "E96A", + "Name": "StorageTape" + }, + { + "Code": "E96D", + "Name": "ChevronUpSmall" + }, + { + "Code": "E96E", + "Name": "ChevronDownSmall" + }, + { + "Code": "E96F", + "Name": "ChevronLeftSmall" + }, + { + "Code": "E970", + "Name": "ChevronRightSmall" + }, + { + "Code": "E971", + "Name": "ChevronUpMed" + }, + { + "Code": "E972", + "Name": "ChevronDownMed" + }, + { + "Code": "E973", + "Name": "ChevronLeftMed" + }, + { + "Code": "E974", + "Name": "ChevronRightMed" + }, + { + "Code": "E975", + "Name": "Devices2" + }, + { + "Code": "E976", + "Name": "ExpandTile" + }, + { + "Code": "E977", + "Name": "PC1" + }, + { + "Code": "E978", + "Name": "PresenceChicklet" + }, + { + "Code": "E979", + "Name": "PresenceChickletVideo" + }, + { + "Code": "E97A", + "Name": "Reply" + }, + { + "Code": "E97B", + "Name": "SetTile" + }, + { + "Code": "E97C", + "Name": "Type" + }, + { + "Code": "E97D", + "Name": "Korean" + }, + { + "Code": "E97E", + "Name": "HalfAlpha" + }, + { + "Code": "E97F", + "Name": "FullAlpha" + }, + { + "Code": "E980", + "Name": "Key12On" + }, + { + "Code": "E981", + "Name": "ChineseChangjie" + }, + { + "Code": "E982", + "Name": "QWERTYOn" + }, + { + "Code": "E983", + "Name": "QWERTYOff" + }, + { + "Code": "E984", + "Name": "ChineseQuick" + }, + { + "Code": "E985", + "Name": "Japanese" + }, + { + "Code": "E986", + "Name": "FullHiragana" + }, + { + "Code": "E987", + "Name": "FullKatakana" + }, + { + "Code": "E988", + "Name": "HalfKatakana" + }, + { + "Code": "E989", + "Name": "ChineseBoPoMoFo" + }, + { + "Code": "E98A", + "Name": "ChinesePinyin" + }, + { + "Code": "E98F", + "Name": "ConstructionCone" + }, + { + "Code": "E990", + "Name": "XboxOneConsole" + }, + { + "Code": "E992", + "Name": "Volume0" + }, + { + "Code": "E993", + "Name": "Volume1" + }, + { + "Code": "E994", + "Name": "Volume2" + }, + { + "Code": "E995", + "Name": "Volume3" + }, + { + "Code": "E996", + "Name": "BatteryUnknown" + }, + { + "Code": "E998", + "Name": "WifiAttentionOverlay" + }, + { + "Code": "E99A", + "Name": "Robot" + }, + { + "Code": "E9A1", + "Name": "TapAndSend" + }, + { + "Code": "E9A6", + "Name": "FitPage" + }, + { + "Code": "E9A8", + "Name": "PasswordKeyShow" + }, + { + "Code": "E9A9", + "Name": "PasswordKeyHide" + }, + { + "Code": "E9AA", + "Name": "BidiLtr" + }, + { + "Code": "E9AB", + "Name": "BidiRtl" + }, + { + "Code": "E9AC", + "Name": "ForwardSm" + }, + { + "Code": "E9AD", + "Name": "CommaKey" + }, + { + "Code": "E9AE", + "Name": "DashKey" + }, + { + "Code": "E9AF", + "Name": "DullSoundKey" + }, + { + "Code": "E9B0", + "Name": "HalfDullSound" + }, + { + "Code": "E9B1", + "Name": "RightDoubleQuote" + }, + { + "Code": "E9B2", + "Name": "LeftDoubleQuote" + }, + { + "Code": "E9B3", + "Name": "PuncKeyRightBottom" + }, + { + "Code": "E9B4", + "Name": "PuncKey1" + }, + { + "Code": "E9B5", + "Name": "PuncKey2" + }, + { + "Code": "E9B6", + "Name": "PuncKey3" + }, + { + "Code": "E9B7", + "Name": "PuncKey4" + }, + { + "Code": "E9B8", + "Name": "PuncKey5" + }, + { + "Code": "E9B9", + "Name": "PuncKey6" + }, + { + "Code": "E9BA", + "Name": "PuncKey9" + }, + { + "Code": "E9BB", + "Name": "PuncKey7" + }, + { + "Code": "E9BC", + "Name": "PuncKey8" + }, + { + "Code": "E9CA", + "Name": "Frigid" + }, + { + "Code": "E9CE", + "Name": "Unknown" + }, + { + "Code": "E9D2", + "Name": "AreaChart" + }, + { + "Code": "E9D5", + "Name": "CheckList" + }, + { + "Code": "E9D9", + "Name": "Diagnostic" + }, + { + "Code": "E9E9", + "Name": "Equalizer" + }, + { + "Code": "E9F3", + "Name": "Process" + }, + { + "Code": "E9F5", + "Name": "Processing" + }, + { + "Code": "E9F9", + "Name": "ReportDocument" + }, + { + "Code": "EA0C", + "Name": "VideoSolid" + }, + { + "Code": "EA0D", + "Name": "MixedMediaBadge" + }, + { + "Code": "EA14", + "Name": "DisconnectDisplay" + }, + { + "Code": "EA18", + "Name": "Shield" + }, + { + "Code": "EA1F", + "Name": "Info2" + }, + { + "Code": "EA21", + "Name": "ActionCenterAsterisk" + }, + { + "Code": "EA24", + "Name": "Beta" + }, + { + "Code": "EA35", + "Name": "SaveCopy" + }, + { + "Code": "EA37", + "Name": "List" + }, + { + "Code": "EA38", + "Name": "Asterisk" + }, + { + "Code": "EA39", + "Name": "ErrorBadge" + }, + { + "Code": "EA3A", + "Name": "CircleRing" + }, + { + "Code": "EA3B", + "Name": "CircleFill" + }, + { + "Code": "EA3C", + "Name": "MergeCall" + }, + { + "Code": "EA3D", + "Name": "PrivateCall" + }, + { + "Code": "EA3F", + "Name": "Record2" + }, + { + "Code": "EA40", + "Name": "AllAppsMirrored" + }, + { + "Code": "EA41", + "Name": "BookmarksMirrored" + }, + { + "Code": "EA42", + "Name": "BulletedListMirrored" + }, + { + "Code": "EA43", + "Name": "CallForwardInternationalMirrored" + }, + { + "Code": "EA44", + "Name": "CallForwardRoamingMirrored" + }, + { + "Code": "EA47", + "Name": "ChromeBackMirrored" + }, + { + "Code": "EA48", + "Name": "ClearSelectionMirrored" + }, + { + "Code": "EA49", + "Name": "ClosePaneMirrored" + }, + { + "Code": "EA4A", + "Name": "ContactInfoMirrored" + }, + { + "Code": "EA4B", + "Name": "DockRightMirrored" + }, + { + "Code": "EA4C", + "Name": "DockLeftMirrored" + }, + { + "Code": "EA4E", + "Name": "ExpandTileMirrored" + }, + { + "Code": "EA4F", + "Name": "GoMirrored" + }, + { + "Code": "EA50", + "Name": "GripperResizeMirrored" + }, + { + "Code": "EA51", + "Name": "HelpMirrored" + }, + { + "Code": "EA52", + "Name": "ImportMirrored" + }, + { + "Code": "EA53", + "Name": "ImportAllMirrored" + }, + { + "Code": "EA54", + "Name": "LeaveChatMirrored" + }, + { + "Code": "EA55", + "Name": "ListMirrored" + }, + { + "Code": "EA56", + "Name": "MailForwardMirrored" + }, + { + "Code": "EA57", + "Name": "MailReplyMirrored" + }, + { + "Code": "EA58", + "Name": "MailReplyAllMirrored" + }, + { + "Code": "EA5B", + "Name": "OpenPaneMirrored" + }, + { + "Code": "EA5C", + "Name": "OpenWithMirrored" + }, + { + "Code": "EA5E", + "Name": "ParkingLocationMirrored" + }, + { + "Code": "EA5F", + "Name": "ResizeMouseMediumMirrored" + }, + { + "Code": "EA60", + "Name": "ResizeMouseSmallMirrored" + }, + { + "Code": "EA61", + "Name": "ResizeMouseTallMirrored" + }, + { + "Code": "EA62", + "Name": "ResizeTouchNarrowerMirrored" + }, + { + "Code": "EA63", + "Name": "SendMirrored" + }, + { + "Code": "EA64", + "Name": "SendFillMirrored" + }, + { + "Code": "EA65", + "Name": "ShowResultsMirrored" + }, + { + "Code": "EA69", + "Name": "Media" + }, + { + "Code": "EA6A", + "Name": "SyncError" + }, + { + "Code": "EA6C", + "Name": "Devices3" + }, + { + "Code": "EA79", + "Name": "SlowMotionOn" + }, + { + "Code": "EA80", + "Name": "Lightbulb" + }, + { + "Code": "EA81", + "Name": "StatusCircle" + }, + { + "Code": "EA82", + "Name": "StatusTriangle" + }, + { + "Code": "EA83", + "Name": "StatusError" + }, + { + "Code": "EA84", + "Name": "StatusWarning" + }, + { + "Code": "EA86", + "Name": "Puzzle" + }, + { + "Code": "EA89", + "Name": "CalendarSolid" + }, + { + "Code": "EA8A", + "Name": "HomeSolid" + }, + { + "Code": "EA8B", + "Name": "ParkingLocationSolid" + }, + { + "Code": "EA8C", + "Name": "ContactSolid" + }, + { + "Code": "EA8D", + "Name": "ConstructionSolid" + }, + { + "Code": "EA8E", + "Name": "AccidentSolid" + }, + { + "Code": "EA8F", + "Name": "Ringer" + }, + { + "Code": "EA90", + "Name": "PDF" + }, + { + "Code": "EA91", + "Name": "ThoughtBubble" + }, + { + "Code": "EA92", + "Name": "HeartBroken" + }, + { + "Code": "EA93", + "Name": "BatteryCharging10" + }, + { + "Code": "EA94", + "Name": "BatterySaver9" + }, + { + "Code": "EA95", + "Name": "BatterySaver10" + }, + { + "Code": "EA97", + "Name": "CallForwardingMirrored" + }, + { + "Code": "EA98", + "Name": "MultiSelectMirrored" + }, + { + "Code": "EA99", + "Name": "Broom" + }, + { + "Code": "EAC2", + "Name": "ForwardCall" + }, + { + "Code": "EADF", + "Name": "Trackers" + }, + { + "Code": "EAFC", + "Name": "Market" + }, + { + "Code": "EB05", + "Name": "PieSingle" + }, + { + "Code": "EB0F", + "Name": "StockUp" + }, + { + "Code": "EB11", + "Name": "StockDown" + }, + { + "Code": "EB3C", + "Name": "Design" + }, + { + "Code": "EB41", + "Name": "Website" + }, + { + "Code": "EB42", + "Name": "Drop" + }, + { + "Code": "EB44", + "Name": "Radar" + }, + { + "Code": "EB47", + "Name": "BusSolid" + }, + { + "Code": "EB48", + "Name": "FerrySolid" + }, + { + "Code": "EB49", + "Name": "StartPointSolid" + }, + { + "Code": "EB4A", + "Name": "StopPointSolid" + }, + { + "Code": "EB4B", + "Name": "EndPointSolid" + }, + { + "Code": "EB4C", + "Name": "AirplaneSolid" + }, + { + "Code": "EB4D", + "Name": "TrainSolid" + }, + { + "Code": "EB4E", + "Name": "WorkSolid" + }, + { + "Code": "EB4F", + "Name": "ReminderFill" + }, + { + "Code": "EB50", + "Name": "Reminder" + }, + { + "Code": "EB51", + "Name": "Heart" + }, + { + "Code": "EB52", + "Name": "HeartFill" + }, + { + "Code": "EB55", + "Name": "EthernetError" + }, + { + "Code": "EB56", + "Name": "EthernetWarning" + }, + { + "Code": "EB57", + "Name": "StatusConnecting1" + }, + { + "Code": "EB58", + "Name": "StatusConnecting2" + }, + { + "Code": "EB59", + "Name": "StatusUnsecure" + }, + { + "Code": "EB5A", + "Name": "WifiError0" + }, + { + "Code": "EB5B", + "Name": "WifiError1" + }, + { + "Code": "EB5C", + "Name": "WifiError2" + }, + { + "Code": "EB5D", + "Name": "WifiError3" + }, + { + "Code": "EB5E", + "Name": "WifiError4" + }, + { + "Code": "EB5F", + "Name": "WifiWarning0" + }, + { + "Code": "EB60", + "Name": "WifiWarning1" + }, + { + "Code": "EB61", + "Name": "WifiWarning2" + }, + { + "Code": "EB62", + "Name": "WifiWarning3" + }, + { + "Code": "EB63", + "Name": "WifiWarning4" + }, + { + "Code": "EB66", + "Name": "Devices4" + }, + { + "Code": "EB67", + "Name": "NUIIris" + }, + { + "Code": "EB68", + "Name": "NUIFace" + }, + { + "Code": "EB77", + "Name": "GatewayRouter" + }, + { + "Code": "EB7E", + "Name": "EditMirrored" + }, + { + "Code": "EB82", + "Name": "NUIFPStartSlideHand" + }, + { + "Code": "EB83", + "Name": "NUIFPStartSlideAction" + }, + { + "Code": "EB84", + "Name": "NUIFPContinueSlideHand" + }, + { + "Code": "EB85", + "Name": "NUIFPContinueSlideAction" + }, + { + "Code": "EB86", + "Name": "NUIFPRollRightHand" + }, + { + "Code": "EB87", + "Name": "NUIFPRollRightHandAction" + }, + { + "Code": "EB88", + "Name": "NUIFPRollLeftHand" + }, + { + "Code": "EB89", + "Name": "NUIFPRollLeftAction" + }, + { + "Code": "EB8A", + "Name": "NUIFPPressHand" + }, + { + "Code": "EB8B", + "Name": "NUIFPPressAction" + }, + { + "Code": "EB8C", + "Name": "NUIFPPressRepeatHand" + }, + { + "Code": "EB8D", + "Name": "NUIFPPressRepeatAction" + }, + { + "Code": "EB90", + "Name": "StatusErrorFull" + }, + { + "Code": "EB91", + "Name": "TaskViewExpanded" + }, + { + "Code": "EB95", + "Name": "Certificate" + }, + { + "Code": "EB96", + "Name": "BackSpaceQWERTYLg" + }, + { + "Code": "EB97", + "Name": "ReturnKeyLg" + }, + { + "Code": "EB9D", + "Name": "FastForward" + }, + { + "Code": "EB9E", + "Name": "Rewind" + }, + { + "Code": "EB9F", + "Name": "Photo2" + }, + { + "Code": "EBA0", + "Name": "MobBattery0" + }, + { + "Code": "EBA1", + "Name": "MobBattery1" + }, + { + "Code": "EBA2", + "Name": "MobBattery2" + }, + { + "Code": "EBA3", + "Name": "MobBattery3" + }, + { + "Code": "EBA4", + "Name": "MobBattery4" + }, + { + "Code": "EBA5", + "Name": "MobBattery5" + }, + { + "Code": "EBA6", + "Name": "MobBattery6" + }, + { + "Code": "EBA7", + "Name": "MobBattery7" + }, + { + "Code": "EBA8", + "Name": "MobBattery8" + }, + { + "Code": "EBA9", + "Name": "MobBattery9" + }, + { + "Code": "EBAA", + "Name": "MobBattery10" + }, + { + "Code": "EBAB", + "Name": "MobBatteryCharging0" + }, + { + "Code": "EBAC", + "Name": "MobBatteryCharging1" + }, + { + "Code": "EBAD", + "Name": "MobBatteryCharging2" + }, + { + "Code": "EBAE", + "Name": "MobBatteryCharging3" + }, + { + "Code": "EBAF", + "Name": "MobBatteryCharging4" + }, + { + "Code": "EBB0", + "Name": "MobBatteryCharging5" + }, + { + "Code": "EBB1", + "Name": "MobBatteryCharging6" + }, + { + "Code": "EBB2", + "Name": "MobBatteryCharging7" + }, + { + "Code": "EBB3", + "Name": "MobBatteryCharging8" + }, + { + "Code": "EBB4", + "Name": "MobBatteryCharging9" + }, + { + "Code": "EBB5", + "Name": "MobBatteryCharging10" + }, + { + "Code": "EBB6", + "Name": "MobBatterySaver0" + }, + { + "Code": "EBB7", + "Name": "MobBatterySaver1" + }, + { + "Code": "EBB8", + "Name": "MobBatterySaver2" + }, + { + "Code": "EBB9", + "Name": "MobBatterySaver3" + }, + { + "Code": "EBBA", + "Name": "MobBatterySaver4" + }, + { + "Code": "EBBB", + "Name": "MobBatterySaver5" + }, + { + "Code": "EBBC", + "Name": "MobBatterySaver6" + }, + { + "Code": "EBBD", + "Name": "MobBatterySaver7" + }, + { + "Code": "EBBE", + "Name": "MobBatterySaver8" + }, + { + "Code": "EBBF", + "Name": "MobBatterySaver9" + }, + { + "Code": "EBC0", + "Name": "MobBatterySaver10" + }, + { + "Code": "EBC3", + "Name": "DictionaryCloud" + }, + { + "Code": "EBC4", + "Name": "ResetDrive" + }, + { + "Code": "EBC5", + "Name": "VolumeBars" + }, + { + "Code": "EBC6", + "Name": "Project" + }, + { + "Code": "EBD2", + "Name": "AdjustHologram" + }, + { + "Code": "EBD3", + "Name": "CloudDownload" + }, + { + "Code": "EBD4", + "Name": "MobWifiCallBars" + }, + { + "Code": "EBD5", + "Name": "MobWifiCall0" + }, + { + "Code": "EBD6", + "Name": "MobWifiCall1" + }, + { + "Code": "EBD7", + "Name": "MobWifiCall2" + }, + { + "Code": "EBD8", + "Name": "MobWifiCall3" + }, + { + "Code": "EBD9", + "Name": "MobWifiCall4" + }, + { + "Code": "EBDA", + "Name": "Family" + }, + { + "Code": "EBDB", + "Name": "LockFeedback" + }, + { + "Code": "EBDE", + "Name": "DeviceDiscovery" + }, + { + "Code": "EBE6", + "Name": "WindDirection" + }, + { + "Code": "EBE7", + "Name": "RightArrowKeyTime0" + }, + { + "Code": "EBE8", + "Name": "Bug" + }, + { + "Code": "EBFC", + "Name": "TabletMode" + }, + { + "Code": "EBFD", + "Name": "StatusCircleLeft" + }, + { + "Code": "EBFE", + "Name": "StatusTriangleLeft" + }, + { + "Code": "EBFF", + "Name": "StatusErrorLeft" + }, + { + "Code": "EC00", + "Name": "StatusWarningLeft" + }, + { + "Code": "EC02", + "Name": "MobBatteryUnknown" + }, + { + "Code": "EC05", + "Name": "NetworkTower" + }, + { + "Code": "EC06", + "Name": "CityNext" + }, + { + "Code": "EC07", + "Name": "CityNext2" + }, + { + "Code": "EC08", + "Name": "Courthouse" + }, + { + "Code": "EC09", + "Name": "Groceries" + }, + { + "Code": "EC0A", + "Name": "Sustainable" + }, + { + "Code": "EC0B", + "Name": "BuildingEnergy" + }, + { + "Code": "EC11", + "Name": "ToggleFilled" + }, + { + "Code": "EC12", + "Name": "ToggleBorder" + }, + { + "Code": "EC13", + "Name": "SliderThumb" + }, + { + "Code": "EC14", + "Name": "ToggleThumb" + }, + { + "Code": "EC15", + "Name": "MiracastLogoSmall" + }, + { + "Code": "EC16", + "Name": "MiracastLogoLarge" + }, + { + "Code": "EC19", + "Name": "PLAP" + }, + { + "Code": "EC1B", + "Name": "Badge" + }, + { + "Code": "EC1E", + "Name": "SignalRoaming" + }, + { + "Code": "EC20", + "Name": "MobileLocked" + }, + { + "Code": "EC24", + "Name": "InsiderHubApp" + }, + { + "Code": "EC25", + "Name": "PersonalFolder" + }, + { + "Code": "EC26", + "Name": "HomeGroup" + }, + { + "Code": "EC27", + "Name": "MyNetwork" + }, + { + "Code": "EC31", + "Name": "KeyboardFull" + }, + { + "Code": "EC32", + "Name": "Cafe" + }, + { + "Code": "EC37", + "Name": "MobSignal1" + }, + { + "Code": "EC38", + "Name": "MobSignal2" + }, + { + "Code": "EC39", + "Name": "MobSignal3" + }, + { + "Code": "EC3A", + "Name": "MobSignal4" + }, + { + "Code": "EC3B", + "Name": "MobSignal5" + }, + { + "Code": "EC3C", + "Name": "MobWifi1" + }, + { + "Code": "EC3D", + "Name": "MobWifi2" + }, + { + "Code": "EC3E", + "Name": "MobWifi3" + }, + { + "Code": "EC3F", + "Name": "MobWifi4" + }, + { + "Code": "EC40", + "Name": "MobAirplane" + }, + { + "Code": "EC41", + "Name": "MobBluetooth" + }, + { + "Code": "EC42", + "Name": "MobActionCenter" + }, + { + "Code": "EC43", + "Name": "MobLocation" + }, + { + "Code": "EC44", + "Name": "MobWifiHotspot" + }, + { + "Code": "EC45", + "Name": "LanguageJpn" + }, + { + "Code": "EC46", + "Name": "MobQuietHours" + }, + { + "Code": "EC47", + "Name": "MobDrivingMode" + }, + { + "Code": "EC48", + "Name": "SpeedOff" + }, + { + "Code": "EC49", + "Name": "SpeedMedium" + }, + { + "Code": "EC4A", + "Name": "SpeedHigh" + }, + { + "Code": "EC4E", + "Name": "ThisPC" + }, + { + "Code": "EC4F", + "Name": "MusicNote" + }, + { + "Code": "EC50", + "Name": "FileExplorer" + }, + { + "Code": "EC51", + "Name": "FileExplorerApp" + }, + { + "Code": "EC52", + "Name": "LeftArrowKeyTime0" + }, + { + "Code": "EC54", + "Name": "MicOff" + }, + { + "Code": "EC55", + "Name": "MicSleep" + }, + { + "Code": "EC56", + "Name": "MicError" + }, + { + "Code": "EC57", + "Name": "PlaybackRate1x" + }, + { + "Code": "EC58", + "Name": "PlaybackRateOther" + }, + { + "Code": "EC59", + "Name": "CashDrawer" + }, + { + "Code": "EC5A", + "Name": "BarcodeScanner" + }, + { + "Code": "EC5B", + "Name": "ReceiptPrinter" + }, + { + "Code": "EC5C", + "Name": "MagStripeReader" + }, + { + "Code": "EC61", + "Name": "CompletedSolid" + }, + { + "Code": "EC64", + "Name": "CompanionApp" + }, + { + "Code": "EC6C", + "Name": "Favicon2" + }, + { + "Code": "EC6D", + "Name": "SwipeRevealArt" + }, + { + "Code": "EC71", + "Name": "MicOn" + }, + { + "Code": "EC72", + "Name": "MicClipping" + }, + { + "Code": "EC74", + "Name": "TabletSelected" + }, + { + "Code": "EC75", + "Name": "MobileSelected" + }, + { + "Code": "EC76", + "Name": "LaptopSelected" + }, + { + "Code": "EC77", + "Name": "TVMonitorSelected" + }, + { + "Code": "EC7A", + "Name": "DeveloperTools" + }, + { + "Code": "EC7E", + "Name": "MobCallForwarding" + }, + { + "Code": "EC7F", + "Name": "MobCallForwardingMirrored" + }, + { + "Code": "EC80", + "Name": "BodyCam" + }, + { + "Code": "EC81", + "Name": "PoliceCar" + }, + { + "Code": "EC87", + "Name": "Draw" + }, + { + "Code": "EC88", + "Name": "DrawSolid" + }, + { + "Code": "EC8A", + "Name": "LowerBrightness" + }, + { + "Code": "EC8F", + "Name": "ScrollUpDown" + }, + { + "Code": "EC92", + "Name": "DateTime" + }, + { + "Code": "EC94", + "Name": "HoloLens" + }, + { + "Code": "ECA5", + "Name": "Tiles" + }, + { + "Code": "ECA7", + "Name": "PartyLeader" + }, + { + "Code": "ECAA", + "Name": "AppIconDefault" + }, + { + "Code": "ECAD", + "Name": "Calories" + }, + { + "Code": "ECAF", + "Name": "POI" + }, + { + "Code": "ECB9", + "Name": "BandBattery0" + }, + { + "Code": "ECBA", + "Name": "BandBattery1" + }, + { + "Code": "ECBB", + "Name": "BandBattery2" + }, + { + "Code": "ECBC", + "Name": "BandBattery3" + }, + { + "Code": "ECBD", + "Name": "BandBattery4" + }, + { + "Code": "ECBE", + "Name": "BandBattery5" + }, + { + "Code": "ECBF", + "Name": "BandBattery6" + }, + { + "Code": "ECC4", + "Name": "AddSurfaceHub" + }, + { + "Code": "ECC5", + "Name": "DevUpdate" + }, + { + "Code": "ECC6", + "Name": "Unit" + }, + { + "Code": "ECC8", + "Name": "AddTo" + }, + { + "Code": "ECC9", + "Name": "RemoveFrom" + }, + { + "Code": "ECCA", + "Name": "RadioBtnOff" + }, + { + "Code": "ECCB", + "Name": "RadioBtnOn" + }, + { + "Code": "ECCC", + "Name": "RadioBullet2" + }, + { + "Code": "ECCD", + "Name": "ExploreContent" + }, + { + "Code": "ECE4", + "Name": "Blocked2" + }, + { + "Code": "ECE7", + "Name": "ScrollMode" + }, + { + "Code": "ECE8", + "Name": "ZoomMode" + }, + { + "Code": "ECE9", + "Name": "PanMode" + }, + { + "Code": "ECF0", + "Name": "WiredUSB" + }, + { + "Code": "ECF1", + "Name": "WirelessUSB" + }, + { + "Code": "ECF3", + "Name": "USBSafeConnect" + }, + { + "Code": "ED0C", + "Name": "ActionCenterNotificationMirrored" + }, + { + "Code": "ED0D", + "Name": "ActionCenterMirrored" + }, + { + "Code": "ED0E", + "Name": "SubscriptionAdd" + }, + { + "Code": "ED10", + "Name": "ResetDevice" + }, + { + "Code": "ED11", + "Name": "SubscriptionAddMirrored" + }, + { + "Code": "ED14", + "Name": "QRCode" + }, + { + "Code": "ED15", + "Name": "Feedback" + }, + { + "Code": "ED1A", + "Name": "Hide" + }, + { + "Code": "ED1E", + "Name": "Subtitles" + }, + { + "Code": "ED1F", + "Name": "SubtitlesAudio" + }, + { + "Code": "ED25", + "Name": "OpenFolderHorizontal" + }, + { + "Code": "ED28", + "Name": "CalendarMirrored" + }, + { + "Code": "ED2A", + "Name": "MobeSIM" + }, + { + "Code": "ED2B", + "Name": "MobeSIMNoProfile" + }, + { + "Code": "ED2C", + "Name": "MobeSIMLocked" + }, + { + "Code": "ED2D", + "Name": "MobeSIMBusy" + }, + { + "Code": "ED2E", + "Name": "SignalError" + }, + { + "Code": "ED2F", + "Name": "StreamingEnterprise" + }, + { + "Code": "ED30", + "Name": "Headphone0" + }, + { + "Code": "ED31", + "Name": "Headphone1" + }, + { + "Code": "ED32", + "Name": "Headphone2" + }, + { + "Code": "ED33", + "Name": "Headphone3" + }, + { + "Code": "ED35", + "Name": "Apps" + }, + { + "Code": "ED39", + "Name": "KeyboardBrightness" + }, + { + "Code": "ED3A", + "Name": "KeyboardLowerBrightness" + }, + { + "Code": "ED3C", + "Name": "SkipBack10" + }, + { + "Code": "ED3D", + "Name": "SkipForward30" + }, + { + "Code": "ED41", + "Name": "TreeFolderFolder" + }, + { + "Code": "ED42", + "Name": "TreeFolderFolderFill" + }, + { + "Code": "ED43", + "Name": "TreeFolderFolderOpen" + }, + { + "Code": "ED44", + "Name": "TreeFolderFolderOpenFill" + }, + { + "Code": "ED47", + "Name": "MultimediaDMP" + }, + { + "Code": "ED4C", + "Name": "KeyboardOneHanded" + }, + { + "Code": "ED4D", + "Name": "Narrator" + }, + { + "Code": "ED53", + "Name": "EmojiTabPeople" + }, + { + "Code": "ED54", + "Name": "EmojiTabSmilesAnimals" + }, + { + "Code": "ED55", + "Name": "EmojiTabCelebrationObjects" + }, + { + "Code": "ED56", + "Name": "EmojiTabFoodPlants" + }, + { + "Code": "ED57", + "Name": "EmojiTabTransitPlaces" + }, + { + "Code": "ED58", + "Name": "EmojiTabSymbols" + }, + { + "Code": "ED59", + "Name": "EmojiTabTextSmiles" + }, + { + "Code": "ED5A", + "Name": "EmojiTabFavorites" + }, + { + "Code": "ED5B", + "Name": "EmojiSwatch" + }, + { + "Code": "ED5C", + "Name": "ConnectApp" + }, + { + "Code": "ED5D", + "Name": "CompanionDeviceFramework" + }, + { + "Code": "ED5E", + "Name": "Ruler" + }, + { + "Code": "ED5F", + "Name": "FingerInking" + }, + { + "Code": "ED60", + "Name": "StrokeErase" + }, + { + "Code": "ED61", + "Name": "PointErase" + }, + { + "Code": "ED62", + "Name": "ClearAllInk" + }, + { + "Code": "ED63", + "Name": "Pencil" + }, + { + "Code": "ED64", + "Name": "Marker" + }, + { + "Code": "ED65", + "Name": "InkingCaret" + }, + { + "Code": "ED66", + "Name": "InkingColorOutline" + }, + { + "Code": "ED67", + "Name": "InkingColorFill" + }, + { + "Code": "EDA2", + "Name": "HardDrive" + }, + { + "Code": "EDA3", + "Name": "NetworkAdapter" + }, + { + "Code": "EDA4", + "Name": "Touchscreen" + }, + { + "Code": "EDA5", + "Name": "NetworkPrinter" + }, + { + "Code": "EDA6", + "Name": "CloudPrinter" + }, + { + "Code": "EDA7", + "Name": "KeyboardShortcut" + }, + { + "Code": "EDA8", + "Name": "BrushSize" + }, + { + "Code": "EDA9", + "Name": "NarratorForward" + }, + { + "Code": "EDAA", + "Name": "NarratorForwardMirrored" + }, + { + "Code": "EDAB", + "Name": "SyncBadge12" + }, + { + "Code": "EDAC", + "Name": "RingerBadge12" + }, + { + "Code": "EDAD", + "Name": "AsteriskBadge12" + }, + { + "Code": "EDAE", + "Name": "ErrorBadge12" + }, + { + "Code": "EDAF", + "Name": "CircleRingBadge12" + }, + { + "Code": "EDB0", + "Name": "CircleFillBadge12" + }, + { + "Code": "EDB1", + "Name": "ImportantBadge12" + }, + { + "Code": "EDB3", + "Name": "MailBadge12" + }, + { + "Code": "EDB4", + "Name": "PauseBadge12" + }, + { + "Code": "EDB5", + "Name": "PlayBadge12" + }, + { + "Code": "EDC6", + "Name": "PenWorkspace" + }, + { + "Code": "EDD5", + "Name": "CaretLeft8" + }, + { + "Code": "EDD6", + "Name": "CaretRight8" + }, + { + "Code": "EDD7", + "Name": "CaretUp8" + }, + { + "Code": "EDD8", + "Name": "CaretDown8" + }, + { + "Code": "EDD9", + "Name": "CaretLeftSolid8" + }, + { + "Code": "EDDA", + "Name": "CaretRightSolid8" + }, + { + "Code": "EDDB", + "Name": "CaretUpSolid8" + }, + { + "Code": "EDDC", + "Name": "CaretDownSolid8" + }, + { + "Code": "EDE0", + "Name": "Strikethrough" + }, + { + "Code": "EDE1", + "Name": "Export" + }, + { + "Code": "EDE2", + "Name": "ExportMirrored" + }, + { + "Code": "EDE3", + "Name": "ButtonMenu" + }, + { + "Code": "EDE4", + "Name": "CloudSearch" + }, + { + "Code": "EDE5", + "Name": "PinyinIMELogo" + }, + { + "Code": "EDFB", + "Name": "CalligraphyPen" + }, + { + "Code": "EE35", + "Name": "ReplyMirrored" + }, + { + "Code": "EE3F", + "Name": "LockscreenDesktop" + }, + { + "Code": "EE40", + "Name": "TaskViewSettings" + }, + { + "Code": "EE47", + "Name": "MiniExpand2Mirrored" + }, + { + "Code": "EE49", + "Name": "MiniContract2Mirrored" + }, + { + "Code": "EE4A", + "Name": "Play36" + }, + { + "Code": "EE56", + "Name": "PenPalette" + }, + { + "Code": "EE57", + "Name": "GuestUser" + }, + { + "Code": "EE63", + "Name": "SettingsBattery" + }, + { + "Code": "EE64", + "Name": "TaskbarPhone" + }, + { + "Code": "EE65", + "Name": "LockScreenGlance" + }, + { + "Code": "EE6F", + "Name": "GenericScan" + }, + { + "Code": "EE71", + "Name": "ImageExport" + }, + { + "Code": "EE77", + "Name": "WifiEthernet" + }, + { + "Code": "EE79", + "Name": "ActionCenterQuiet" + }, + { + "Code": "EE7A", + "Name": "ActionCenterQuietNotification" + }, + { + "Code": "EE92", + "Name": "TrackersMirrored" + }, + { + "Code": "EE93", + "Name": "DateTimeMirrored" + }, + { + "Code": "EE94", + "Name": "Wheel" + }, + { + "Code": "EEA3", + "Name": "VirtualMachineGroup" + }, + { + "Code": "EECA", + "Name": "ButtonView2" + }, + { + "Code": "EF15", + "Name": "PenWorkspaceMirrored" + }, + { + "Code": "EF16", + "Name": "PenPaletteMirrored" + }, + { + "Code": "EF17", + "Name": "StrokeEraseMirrored" + }, + { + "Code": "EF18", + "Name": "PointEraseMirrored" + }, + { + "Code": "EF19", + "Name": "ClearAllInkMirrored" + }, + { + "Code": "EF1F", + "Name": "BackgroundToggle" + }, + { + "Code": "EF20", + "Name": "Marquee" + }, + { + "Code": "EF2C", + "Name": "ChromeCloseContrast" + }, + { + "Code": "EF2D", + "Name": "ChromeMinimizeContrast" + }, + { + "Code": "EF2E", + "Name": "ChromeMaximizeContrast" + }, + { + "Code": "EF2F", + "Name": "ChromeRestoreContrast" + }, + { + "Code": "EF31", + "Name": "TrafficLight" + }, + { + "Code": "EF3B", + "Name": "Replay" + }, + { + "Code": "EF3C", + "Name": "Eyedropper" + }, + { + "Code": "EF3D", + "Name": "LineDisplay" + }, + { + "Code": "EF3E", + "Name": "PINPad" + }, + { + "Code": "EF3F", + "Name": "SignatureCapture" + }, + { + "Code": "EF40", + "Name": "ChipCardCreditCardReader" + }, + { + "Code": "EF42", + "Name": "MarketDown" + }, + { + "Code": "EF58", + "Name": "PlayerSettings" + }, + { + "Code": "EF6B", + "Name": "LandscapeOrientation" + }, + { + "Code": "EF90", + "Name": "Flow" + }, + { + "Code": "EFA5", + "Name": "Touchpad" + }, + { + "Code": "EFA9", + "Name": "Speech" + }, + { + "Code": "F000", + "Name": "KnowledgeArticle" + }, + { + "Code": "F003", + "Name": "Relationship" + }, + { + "Code": "F012", + "Name": "ZipFolder" + }, + { + "Code": "F080", + "Name": "DefaultAPN" + }, + { + "Code": "F081", + "Name": "UserAPN" + }, + { + "Code": "F085", + "Name": "DoublePinyin" + }, + { + "Code": "F08C", + "Name": "BlueLight" + }, + { + "Code": "F08D", + "Name": "CaretSolidLeft" + }, + { + "Code": "F08E", + "Name": "CaretSolidDown" + }, + { + "Code": "F08F", + "Name": "CaretSolidRight" + }, + { + "Code": "F090", + "Name": "CaretSolidUp" + }, + { + "Code": "F093", + "Name": "ButtonA" + }, + { + "Code": "F094", + "Name": "ButtonB" + }, + { + "Code": "F095", + "Name": "ButtonY" + }, + { + "Code": "F096", + "Name": "ButtonX" + }, + { + "Code": "F0AD", + "Name": "ArrowUp8" + }, + { + "Code": "F0AE", + "Name": "ArrowDown8" + }, + { + "Code": "F0AF", + "Name": "ArrowRight8" + }, + { + "Code": "F0B0", + "Name": "ArrowLeft8" + }, + { + "Code": "F0B2", + "Name": "QuarentinedItems" + }, + { + "Code": "F0B3", + "Name": "QuarentinedItemsMirrored" + }, + { + "Code": "F0B4", + "Name": "Protractor" + }, + { + "Code": "F0B5", + "Name": "ChecklistMirrored" + }, + { + "Code": "F0B6", + "Name": "StatusCircle7" + }, + { + "Code": "F0B7", + "Name": "StatusCheckmark7" + }, + { + "Code": "F0B8", + "Name": "StatusErrorCircle7" + }, + { + "Code": "F0B9", + "Name": "Connected" + }, + { + "Code": "F0C6", + "Name": "PencilFill" + }, + { + "Code": "F0C7", + "Name": "CalligraphyFill" + }, + { + "Code": "F0CA", + "Name": "QuarterStarLeft" + }, + { + "Code": "F0CB", + "Name": "QuarterStarRight" + }, + { + "Code": "F0CC", + "Name": "ThreeQuarterStarLeft" + }, + { + "Code": "F0CD", + "Name": "ThreeQuarterStarRight" + }, + { + "Code": "F0CE", + "Name": "QuietHoursBadge12" + }, + { + "Code": "F0D2", + "Name": "BackMirrored" + }, + { + "Code": "F0D3", + "Name": "ForwardMirrored" + }, + { + "Code": "F0D5", + "Name": "ChromeBackContrast" + }, + { + "Code": "F0D6", + "Name": "ChromeBackContrastMirrored" + }, + { + "Code": "F0D7", + "Name": "ChromeBackToWindowContrast" + }, + { + "Code": "F0D8", + "Name": "ChromeFullScreenContrast" + }, + { + "Code": "F0E2", + "Name": "GridView" + }, + { + "Code": "F0E3", + "Name": "ClipboardList" + }, + { + "Code": "F0E4", + "Name": "ClipboardListMirrored" + }, + { + "Code": "F0E5", + "Name": "OutlineQuarterStarLeft" + }, + { + "Code": "F0E6", + "Name": "OutlineQuarterStarRight" + }, + { + "Code": "F0E7", + "Name": "OutlineHalfStarLeft" + }, + { + "Code": "F0E8", + "Name": "OutlineHalfStarRight" + }, + { + "Code": "F0E9", + "Name": "OutlineThreeQuarterStarLeft" + }, + { + "Code": "F0EA", + "Name": "OutlineThreeQuarterStarRight" + }, + { + "Code": "F0EB", + "Name": "SpatialVolume0" + }, + { + "Code": "F0EC", + "Name": "SpatialVolume1" + }, + { + "Code": "F0ED", + "Name": "SpatialVolume2" + }, + { + "Code": "F0EE", + "Name": "SpatialVolume3" + }, + { + "Code": "F0EF", + "Name": "ApplicationGuard" + }, + { + "Code": "F0F7", + "Name": "OutlineStarLeftHalf" + }, + { + "Code": "F0F8", + "Name": "OutlineStarRightHalf" + }, + { + "Code": "F0F9", + "Name": "ChromeAnnotateContrast" + }, + { + "Code": "F0FB", + "Name": "DefenderBadge12" + }, + { + "Code": "F103", + "Name": "DetachablePC" + }, + { + "Code": "F108", + "Name": "LeftStick" + }, + { + "Code": "F109", + "Name": "RightStick" + }, + { + "Code": "F10A", + "Name": "TriggerLeft" + }, + { + "Code": "F10B", + "Name": "TriggerRight" + }, + { + "Code": "F10C", + "Name": "BumperLeft" + }, + { + "Code": "F10D", + "Name": "BumperRight" + }, + { + "Code": "F10E", + "Name": "Dpad" + }, + { + "Code": "F110", + "Name": "EnglishPunctuation" + }, + { + "Code": "F111", + "Name": "ChinesePunctuation" + }, + { + "Code": "F119", + "Name": "HMD" + }, + { + "Code": "F11B", + "Name": "CtrlSpatialRight" + }, + { + "Code": "F126", + "Name": "PaginationDotOutline10" + }, + { + "Code": "F127", + "Name": "PaginationDotSolid10" + }, + { + "Code": "F128", + "Name": "StrokeErase2" + }, + { + "Code": "F129", + "Name": "SmallErase" + }, + { + "Code": "F12A", + "Name": "LargeErase" + }, + { + "Code": "F12B", + "Name": "FolderHorizontal" + }, + { + "Code": "F12E", + "Name": "MicrophoneListening" + }, + { + "Code": "F12F", + "Name": "StatusExclamationCircle7" + }, + { + "Code": "F131", + "Name": "Video360" + }, + { + "Code": "F133", + "Name": "GiftboxOpen" + }, + { + "Code": "F136", + "Name": "StatusCircleOuter" + }, + { + "Code": "F137", + "Name": "StatusCircleInner" + }, + { + "Code": "F138", + "Name": "StatusCircleRing" + }, + { + "Code": "F139", + "Name": "StatusTriangleOuter" + }, + { + "Code": "F13A", + "Name": "StatusTriangleInner" + }, + { + "Code": "F13B", + "Name": "StatusTriangleExclamation" + }, + { + "Code": "F13C", + "Name": "StatusCircleExclamation" + }, + { + "Code": "F13D", + "Name": "StatusCircleErrorX" + }, + { + "Code": "F13E", + "Name": "StatusCircleCheckmark" + }, + { + "Code": "F13F", + "Name": "StatusCircleInfo" + }, + { + "Code": "F140", + "Name": "StatusCircleBlock" + }, + { + "Code": "F141", + "Name": "StatusCircleBlock2" + }, + { + "Code": "F142", + "Name": "StatusCircleQuestionMark" + }, + { + "Code": "F143", + "Name": "StatusCircleSync" + }, + { + "Code": "F146", + "Name": "Dial1" + }, + { + "Code": "F147", + "Name": "Dial2" + }, + { + "Code": "F148", + "Name": "Dial3" + }, + { + "Code": "F149", + "Name": "Dial4" + }, + { + "Code": "F14A", + "Name": "Dial5" + }, + { + "Code": "F14B", + "Name": "Dial6" + }, + { + "Code": "F14C", + "Name": "Dial7" + }, + { + "Code": "F14D", + "Name": "Dial8" + }, + { + "Code": "F14E", + "Name": "Dial9" + }, + { + "Code": "F14F", + "Name": "Dial10" + }, + { + "Code": "F150", + "Name": "Dial11" + }, + { + "Code": "F151", + "Name": "Dial12" + }, + { + "Code": "F152", + "Name": "Dial13" + }, + { + "Code": "F153", + "Name": "Dial14" + }, + { + "Code": "F154", + "Name": "Dial15" + }, + { + "Code": "F155", + "Name": "Dial16" + }, + { + "Code": "F156", + "Name": "DialShape1" + }, + { + "Code": "F157", + "Name": "DialShape2" + }, + { + "Code": "F158", + "Name": "DialShape3" + }, + { + "Code": "F159", + "Name": "DialShape4" + }, + { + "Code": "F15F", + "Name": "ClosedCaptionsInternational" + }, + { + "Code": "F161", + "Name": "TollSolid" + }, + { + "Code": "F163", + "Name": "TrafficCongestionSolid" + }, + { + "Code": "F164", + "Name": "ExploreContentSingle" + }, + { + "Code": "F165", + "Name": "CollapseContent" + }, + { + "Code": "F166", + "Name": "CollapseContentSingle" + }, + { + "Code": "F167", + "Name": "InfoSolid" + }, + { + "Code": "F168", + "Name": "GroupList" + }, + { + "Code": "F169", + "Name": "CaretBottomRightSolidCenter8" + }, + { + "Code": "F16A", + "Name": "ProgressRingDots" + }, + { + "Code": "F16B", + "Name": "Checkbox14" + }, + { + "Code": "F16C", + "Name": "CheckboxComposite14" + }, + { + "Code": "F16D", + "Name": "CheckboxIndeterminateCombo14" + }, + { + "Code": "F16E", + "Name": "CheckboxIndeterminateCombo" + }, + { + "Code": "F175", + "Name": "StatusPause7" + }, + { + "Code": "F17F", + "Name": "CharacterAppearance" + }, + { + "Code": "F180", + "Name": "Lexicon" + }, + { + "Code": "F182", + "Name": "ScreenTime" + }, + { + "Code": "F191", + "Name": "HeadlessDevice" + }, + { + "Code": "F193", + "Name": "NetworkSharing" + }, + { + "Code": "F19D", + "Name": "EyeGaze" + }, + { + "Code": "F19E", + "Name": "ToggleLeft" + }, + { + "Code": "F19F", + "Name": "ToggleRight" + }, + { + "Code": "F1AD", + "Name": "WindowsInsider" + }, + { + "Code": "F1CB", + "Name": "ChromeSwitch" + }, + { + "Code": "F1CC", + "Name": "ChromeSwitchContast" + }, + { + "Code": "F1D8", + "Name": "StatusCheckmark" + }, + { + "Code": "F1D9", + "Name": "StatusCheckmarkLeft" + }, + { + "Code": "F20C", + "Name": "KeyboardLeftAligned" + }, + { + "Code": "F20D", + "Name": "KeyboardRightAligned" + }, + { + "Code": "F210", + "Name": "KeyboardSettings" + }, + { + "Code": "F211", + "Name": "NetworkPhysical" + }, + { + "Code": "F22C", + "Name": "IOT" + }, + { + "Code": "F22E", + "Name": "UnknownMirrored" + }, + { + "Code": "F246", + "Name": "ViewDashboard" + }, + { + "Code": "F259", + "Name": "ExploitProtectionSettings" + }, + { + "Code": "F260", + "Name": "KeyboardNarrow" + }, + { + "Code": "F261", + "Name": "Keyboard12Key" + }, + { + "Code": "F26B", + "Name": "KeyboardDock" + }, + { + "Code": "F26C", + "Name": "KeyboardUndock" + }, + { + "Code": "F26D", + "Name": "KeyboardLeftDock" + }, + { + "Code": "F26E", + "Name": "KeyboardRightDock" + }, + { + "Code": "F270", + "Name": "Ear" + }, + { + "Code": "F271", + "Name": "PointerHand" + }, + { + "Code": "F272", + "Name": "Bullseye" + }, + { + "Code": "F28B", + "Name": "DocumentApproval" + }, + { + "Code": "F2B7", + "Name": "LocaleLanguage" + }, + { + "Code": "F32A", + "Name": "PassiveAuthentication" + }, + { + "Code": "F354", + "Name": "ColorSolid" + }, + { + "Code": "F384", + "Name": "NetworkOffline" + }, + { + "Code": "F385", + "Name": "NetworkConnected" + }, + { + "Code": "F386", + "Name": "NetworkConnectedCheckmark" + }, + { + "Code": "F3B1", + "Name": "SignOut" + }, + { + "Code": "F3CC", + "Name": "StatusInfo" + }, + { + "Code": "F3CD", + "Name": "StatusInfoLeft" + }, + { + "Code": "F3E2", + "Name": "NearbySharing" + }, + { + "Code": "F3E7", + "Name": "CtrlSpatialLeft" + }, + { + "Code": "F404", + "Name": "InteractiveDashboard" + }, + { + "Code": "F405", + "Name": "DeclineCall" + }, + { + "Code": "F406", + "Name": "ClippingTool" + }, + { + "Code": "F407", + "Name": "RectangularClipping" + }, + { + "Code": "F408", + "Name": "FreeFormClipping" + }, + { + "Code": "F413", + "Name": "CopyTo" + }, + { + "Code": "F427", + "Name": "IDBadge" + }, + { + "Code": "F439", + "Name": "DynamicLock" + }, + { + "Code": "F45E", + "Name": "PenTips" + }, + { + "Code": "F45F", + "Name": "PenTipsMirrored" + }, + { + "Code": "F460", + "Name": "HWPJoin" + }, + { + "Code": "F461", + "Name": "HWPInsert" + }, + { + "Code": "F462", + "Name": "HWPStrikeThrough" + }, + { + "Code": "F463", + "Name": "HWPScratchOut" + }, + { + "Code": "F464", + "Name": "HWPSplit" + }, + { + "Code": "F465", + "Name": "HWPNewLine" + }, + { + "Code": "F466", + "Name": "HWPOverwrite" + }, + { + "Code": "F473", + "Name": "MobWifiWarning1" + }, + { + "Code": "F474", + "Name": "MobWifiWarning2" + }, + { + "Code": "F475", + "Name": "MobWifiWarning3" + }, + { + "Code": "F476", + "Name": "MobWifiWarning4" + }, + { + "Code": "F47F", + "Name": "MicLocationCombo" + }, + { + "Code": "F49A", + "Name": "Globe2" + }, + { + "Code": "F4A5", + "Name": "SpecialEffectSize" + }, + { + "Code": "F4A9", + "Name": "GIF" + }, + { + "Code": "F4AA", + "Name": "Sticker2" + }, + { + "Code": "F4BE", + "Name": "SurfaceHubSelected" + }, + { + "Code": "F4BF", + "Name": "HoloLensSelected" + }, + { + "Code": "F4C0", + "Name": "Earbud" + }, + { + "Code": "F4C3", + "Name": "MixVolumes" + }, + { + "Code": "F540", + "Name": "Safe" + }, + { + "Code": "F552", + "Name": "LaptopSecure" + }, + { + "Code": "F56D", + "Name": "PrintDefault" + }, + { + "Code": "F56E", + "Name": "PageMirrored" + }, + { + "Code": "F56F", + "Name": "LandscapeOrientationMirrored" + }, + { + "Code": "F570", + "Name": "ColorOff" + }, + { + "Code": "F571", + "Name": "PrintAllPages" + }, + { + "Code": "F572", + "Name": "PrintCustomRange" + }, + { + "Code": "F573", + "Name": "PageMarginPortraitNarrow" + }, + { + "Code": "F574", + "Name": "PageMarginPortraitNormal" + }, + { + "Code": "F575", + "Name": "PageMarginPortraitModerate" + }, + { + "Code": "F576", + "Name": "PageMarginPortraitWide" + }, + { + "Code": "F577", + "Name": "PageMarginLandscapeNarrow" + }, + { + "Code": "F578", + "Name": "PageMarginLandscapeNormal" + }, + { + "Code": "F579", + "Name": "PageMarginLandscapeModerate" + }, + { + "Code": "F57A", + "Name": "PageMarginLandscapeWide" + }, + { + "Code": "F57B", + "Name": "CollateLandscape" + }, + { + "Code": "F57C", + "Name": "CollatePortrait" + }, + { + "Code": "F57D", + "Name": "CollatePortraitSeparated" + }, + { + "Code": "F57E", + "Name": "DuplexLandscapeOneSided" + }, + { + "Code": "F57F", + "Name": "DuplexLandscapeOneSidedMirrored" + }, + { + "Code": "F580", + "Name": "DuplexLandscapeTwoSidedLongEdge" + }, + { + "Code": "F581", + "Name": "DuplexLandscapeTwoSidedLongEdgeMirrored" + }, + { + "Code": "F582", + "Name": "DuplexLandscapeTwoSidedShortEdge" + }, + { + "Code": "F583", + "Name": "DuplexLandscapeTwoSidedShortEdgeMirrored" + }, + { + "Code": "F584", + "Name": "DuplexPortraitOneSided" + }, + { + "Code": "F585", + "Name": "DuplexPortraitOneSidedMirrored" + }, + { + "Code": "F586", + "Name": "DuplexPortraitTwoSidedLongEdge" + }, + { + "Code": "F587", + "Name": "DuplexPortraitTwoSidedLongEdgeMirrored" + }, + { + "Code": "F588", + "Name": "DuplexPortraitTwoSidedShortEdge" + }, + { + "Code": "F589", + "Name": "DuplexPortraitTwoSidedShortEdgeMirrored" + }, + { + "Code": "F58A", + "Name": "PPSOneLandscape" + }, + { + "Code": "F58B", + "Name": "PPSTwoLandscape" + }, + { + "Code": "F58C", + "Name": "PPSTwoPortrait" + }, + { + "Code": "F58D", + "Name": "PPSFourLandscape" + }, + { + "Code": "F58E", + "Name": "PPSFourPortrait" + }, + { + "Code": "F58F", + "Name": "HolePunchOff" + }, + { + "Code": "F590", + "Name": "HolePunchPortraitLeft" + }, + { + "Code": "F591", + "Name": "HolePunchPortraitRight" + }, + { + "Code": "F592", + "Name": "HolePunchPortraitTop" + }, + { + "Code": "F593", + "Name": "HolePunchPortraitBottom" + }, + { + "Code": "F594", + "Name": "HolePunchLandscapeLeft" + }, + { + "Code": "F595", + "Name": "HolePunchLandscapeRight" + }, + { + "Code": "F596", + "Name": "HolePunchLandscapeTop" + }, + { + "Code": "F597", + "Name": "HolePunchLandscapeBottom" + }, + { + "Code": "F598", + "Name": "StaplingOff" + }, + { + "Code": "F599", + "Name": "StaplingPortraitTopLeft" + }, + { + "Code": "F59A", + "Name": "StaplingPortraitTopRight" + }, + { + "Code": "F59B", + "Name": "StaplingPortraitBottomRight" + }, + { + "Code": "F59C", + "Name": "StaplingPortraitTwoLeft" + }, + { + "Code": "F59D", + "Name": "StaplingPortraitTwoRight" + }, + { + "Code": "F59E", + "Name": "StaplingPortraitTwoTop" + }, + { + "Code": "F59F", + "Name": "StaplingPortraitTwoBottom" + }, + { + "Code": "F5A0", + "Name": "StaplingPortraitBookBinding" + }, + { + "Code": "F5A1", + "Name": "StaplingLandscapeTopLeft" + }, + { + "Code": "F5A2", + "Name": "StaplingLandscapeTopRight" + }, + { + "Code": "F5A3", + "Name": "StaplingLandscapeBottomLeft" + }, + { + "Code": "F5A4", + "Name": "StaplingLandscapeBottomRight" + }, + { + "Code": "F5A5", + "Name": "StaplingLandscapeTwoLeft" + }, + { + "Code": "F5A6", + "Name": "StaplingLandscapeTwoRight" + }, + { + "Code": "F5A7", + "Name": "StaplingLandscapeTwoTop" + }, + { + "Code": "F5A8", + "Name": "StaplingLandscapeTwoBottom" + }, + { + "Code": "F5A9", + "Name": "StaplingLandscapeBookBinding" + }, + { + "Code": "F5AA", + "Name": "StatusDataTransferRoaming" + }, + { + "Code": "F5AB", + "Name": "MobSIMError" + }, + { + "Code": "F5AC", + "Name": "CollateLandscapeSeparated" + }, + { + "Code": "F5AD", + "Name": "PPSOnePortrait" + }, + { + "Code": "F5AE", + "Name": "StaplingPortraitBottomLeft" + }, + { + "Code": "F5B0", + "Name": "PlaySolid" + }, + { + "Code": "F5E7", + "Name": "RepeatOff" + }, + { + "Code": "F5ED", + "Name": "Set" + }, + { + "Code": "F5EE", + "Name": "SetSolid" + }, + { + "Code": "F5EF", + "Name": "FuzzyReading" + }, + { + "Code": "F5F2", + "Name": "VerticalBattery0" + }, + { + "Code": "F5F3", + "Name": "VerticalBattery1" + }, + { + "Code": "F5F4", + "Name": "VerticalBattery2" + }, + { + "Code": "F5F5", + "Name": "VerticalBattery3" + }, + { + "Code": "F5F6", + "Name": "VerticalBattery4" + }, + { + "Code": "F5F7", + "Name": "VerticalBattery5" + }, + { + "Code": "F5F8", + "Name": "VerticalBattery6" + }, + { + "Code": "F5F9", + "Name": "VerticalBattery7" + }, + { + "Code": "F5FA", + "Name": "VerticalBattery8" + }, + { + "Code": "F5FB", + "Name": "VerticalBattery9" + }, + { + "Code": "F5FC", + "Name": "VerticalBattery10" + }, + { + "Code": "F5FD", + "Name": "VerticalBatteryCharging0" + }, + { + "Code": "F5FE", + "Name": "VerticalBatteryCharging1" + }, + { + "Code": "F5FF", + "Name": "VerticalBatteryCharging2" + }, + { + "Code": "F600", + "Name": "VerticalBatteryCharging3" + }, + { + "Code": "F601", + "Name": "VerticalBatteryCharging4" + }, + { + "Code": "F602", + "Name": "VerticalBatteryCharging5" + }, + { + "Code": "F603", + "Name": "VerticalBatteryCharging6" + }, + { + "Code": "F604", + "Name": "VerticalBatteryCharging7" + }, + { + "Code": "F605", + "Name": "VerticalBatteryCharging8" + }, + { + "Code": "F606", + "Name": "VerticalBatteryCharging9" + }, + { + "Code": "F607", + "Name": "VerticalBatteryCharging10" + }, + { + "Code": "F608", + "Name": "VerticalBatteryUnknown" + }, + { + "Code": "F618", + "Name": "SIMError" + }, + { + "Code": "F619", + "Name": "SIMMissing" + }, + { + "Code": "F61A", + "Name": "SIMLock" + }, + { + "Code": "F61B", + "Name": "eSIM" + }, + { + "Code": "F61C", + "Name": "eSIMNoProfile" + }, + { + "Code": "F61D", + "Name": "eSIMLocked" + }, + { + "Code": "F61E", + "Name": "eSIMBusy" + }, + { + "Code": "F61F", + "Name": "NoiseCancelation" + }, + { + "Code": "F620", + "Name": "NoiseCancelationOff" + }, + { + "Code": "F623", + "Name": "MusicSharing" + }, + { + "Code": "F624", + "Name": "MusicSharingOff" + }, + { + "Code": "F63C", + "Name": "CircleShapeSolid" + }, + { + "Code": "F657", + "Name": "WifiCallBars" + }, + { + "Code": "F658", + "Name": "WifiCall0" + }, + { + "Code": "F659", + "Name": "WifiCall1" + }, + { + "Code": "F65A", + "Name": "WifiCall2" + }, + { + "Code": "F65B", + "Name": "WifiCall3" + }, + { + "Code": "F65C", + "Name": "WifiCall4" + }, + { + "Code": "F69E", + "Name": "CHTLanguageBar" + }, + { + "Code": "F6A9", + "Name": "ComposeMode" + }, + { + "Code": "F6B8", + "Name": "ExpressiveInputEntry" + }, + { + "Code": "F6BA", + "Name": "EmojiTabMoreSymbols" + }, + { + "Code": "F6FA", + "Name": "WebSearch" + }, + { + "Code": "F712", + "Name": "Kiosk" + }, + { + "Code": "F714", + "Name": "RTTLogo" + }, + { + "Code": "F715", + "Name": "VoiceCall" + }, + { + "Code": "F716", + "Name": "GoToMessage" + }, + { + "Code": "F71A", + "Name": "ReturnToCall" + }, + { + "Code": "F71C", + "Name": "StartPresenting" + }, + { + "Code": "F71D", + "Name": "StopPresenting" + }, + { + "Code": "F71E", + "Name": "ProductivityMode" + }, + { + "Code": "F738", + "Name": "SetHistoryStatus" + }, + { + "Code": "F739", + "Name": "SetHistoryStatus2" + }, + { + "Code": "F73D", + "Name": "Keyboardsettings20" + }, + { + "Code": "F73E", + "Name": "OneHandedRight20" + }, + { + "Code": "F73F", + "Name": "OneHandedLeft20" + }, + { + "Code": "F740", + "Name": "Split20" + }, + { + "Code": "F741", + "Name": "Full20" + }, + { + "Code": "F742", + "Name": "Handwriting20" + }, + { + "Code": "F743", + "Name": "ChevronLeft20" + }, + { + "Code": "F744", + "Name": "ChevronLeft32" + }, + { + "Code": "F745", + "Name": "ChevronRight20" + }, + { + "Code": "F746", + "Name": "ChevronRight32" + }, + { + "Code": "F763", + "Name": "Event12" + }, + { + "Code": "F781", + "Name": "MicOff2" + }, + { + "Code": "F785", + "Name": "DeliveryOptimization" + }, + { + "Code": "F78A", + "Name": "CancelMedium" + }, + { + "Code": "F78B", + "Name": "SearchMedium" + }, + { + "Code": "F78C", + "Name": "AcceptMedium" + }, + { + "Code": "F78D", + "Name": "RevealPasswordMedium" + }, + { + "Code": "F7AD", + "Name": "DeleteWord" + }, + { + "Code": "F7AE", + "Name": "DeleteWordFill" + }, + { + "Code": "F7AF", + "Name": "DeleteLines" + }, + { + "Code": "F7B0", + "Name": "DeleteLinesFill" + }, + { + "Code": "F7B1", + "Name": "InstertWords" + }, + { + "Code": "F7B2", + "Name": "InstertWordsFill" + }, + { + "Code": "F7B3", + "Name": "JoinWords" + }, + { + "Code": "F7B4", + "Name": "JoinWordsFill" + }, + { + "Code": "F7B5", + "Name": "OverwriteWords" + }, + { + "Code": "F7B6", + "Name": "OverwriteWordsFill" + }, + { + "Code": "F7B7", + "Name": "AddNewLine" + }, + { + "Code": "F7B8", + "Name": "AddNewLineFill" + }, + { + "Code": "F7B9", + "Name": "OverwriteWordsKorean" + }, + { + "Code": "F7BA", + "Name": "OverwriteWordsFillKorean" + }, + { + "Code": "F7BB", + "Name": "EducationIcon" + }, + { + "Code": "F7ED", + "Name": "WindowSnipping" + }, + { + "Code": "F7EE", + "Name": "VideoCapture" + }, + { + "Code": "F809", + "Name": "StatusSecured" + }, + { + "Code": "F83B", + "Name": "NarratorApp" + }, + { + "Code": "F83D", + "Name": "PowerButtonUpdate" + }, + { + "Code": "F83E", + "Name": "RestartUpdate" + }, + { + "Code": "F83F", + "Name": "UpdateStatusDot" + }, + { + "Code": "F847", + "Name": "Eject" + }, + { + "Code": "F87B", + "Name": "Spelling" + }, + { + "Code": "F87C", + "Name": "SpellingKorean" + }, + { + "Code": "F87D", + "Name": "SpellingSerbian" + }, + { + "Code": "F87E", + "Name": "SpellingChinese" + }, + { + "Code": "F89A", + "Name": "FolderSelect" + }, + { + "Code": "F8A5", + "Name": "SmartScreen" + }, + { + "Code": "F8A6", + "Name": "ExploitProtection" + }, + { + "Code": "F8AA", + "Name": "AddBold" + }, + { + "Code": "F8AB", + "Name": "SubtractBold" + }, + { + "Code": "F8AC", + "Name": "BackSolidBold" + }, + { + "Code": "F8AD", + "Name": "ForwardSolidBold" + }, + { + "Code": "F8AE", + "Name": "PauseBold" + }, + { + "Code": "F8AF", + "Name": "ClickSolid" + }, + { + "Code": "F8B0", + "Name": "SettingsSolid" + }, + { + "Code": "F8B1", + "Name": "MicrophoneSolidBold" + }, + { + "Code": "F8B2", + "Name": "SpeechSolidBold" + }, + { + "Code": "F8B3", + "Name": "ClickedOutLoudSolidBold" + } +] \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Models/SymbolIconData.cs b/source/RevitLookup.UI.Playground/Client/Models/SymbolIconData.cs new file mode 100644 index 000000000..3c54bf251 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Models/SymbolIconData.cs @@ -0,0 +1,14 @@ +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Client.Models; + +/// +/// IconData class for icons in icon page +/// +public sealed class SymbolIconData +{ + public required string Name { get; init; } + public required SymbolRegular Icon { get; init; } + public required string Code { get; init; } + public string TextGlyph => $"&#x{Code};"; +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductIcon.png b/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductIcon.png new file mode 100644 index 000000000..8e012ed13 Binary files /dev/null and b/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductIcon.png differ diff --git a/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductLogo.png b/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductLogo.png new file mode 100644 index 000000000..7236de89e Binary files /dev/null and b/source/RevitLookup.UI.Playground/Client/Resources/Images/ProductLogo.png differ diff --git a/source/RevitLookup.UI.Playground/Client/Services/ViewModelServices.cs b/source/RevitLookup.UI.Playground/Client/Services/ViewModelServices.cs new file mode 100644 index 000000000..d4dd9693a --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Services/ViewModelServices.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace RevitLookup.UI.Playground.Client.Services; + +public static class ViewModelServices +{ + public static void RegisterViewModels(this IServiceCollection services) + { + services.Scan(selector => selector.FromCallingAssembly() + .AddClasses(filter => filter.InNamespaces("RevitLookup.UI.Playground.Client.ViewModels")) + .AsSelf() + .WithScopedLifetime() + .AddClasses(filter => filter.NotInNamespaces("RevitLookup.UI.Playground.Client.ViewModels").Where(type => type.Name.EndsWith("ViewModel"))) + .AsImplementedInterfaces(type => type.Name.EndsWith("ViewModel")) + .WithScopedLifetime()); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Services/ViewServices.cs b/source/RevitLookup.UI.Playground/Client/Services/ViewServices.cs new file mode 100644 index 000000000..774f42b72 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Services/ViewServices.cs @@ -0,0 +1,30 @@ +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using Wpf.Ui.Abstractions.Controls; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Client.Services; + +public static class ViewServices +{ + public static void RegisterViews(this IServiceCollection services) + { + services.Scan(selector => selector.FromAssemblyOf() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithScopedLifetime() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithTransientLifetime() + .AddClasses(filter => + { + filter.AssignableTo(); + filter.Where(type => type.IsAssignableTo(typeof(INavigableView))); + }).AsSelf().WithScopedLifetime() + .AddClasses(filter => + { + filter.AssignableTo(); + filter.Where(type => !type.IsAssignableTo(typeof(INavigableView))); + }).AsSelf().WithTransientLifetime()); + + services.Scan(selector => selector.FromCallingAssembly() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithScopedLifetime() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithScopedLifetime()); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DashboardViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DashboardViewModel.cs new file mode 100644 index 000000000..0ac7c638d --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DashboardViewModel.cs @@ -0,0 +1,29 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using RevitLookup.UI.Playground.Client.Views.Pages; +using Wpf.Ui; + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages; + +[UsedImplicitly] +public sealed partial class DashboardViewModel(INavigationService navigationService) : ObservableObject +{ + [RelayCommand] + private void NavigateToWindowsPage() + { + navigationService.NavigateWithHierarchy(typeof(WindowsPage)); + } + + [RelayCommand] + private void NavigateToPagesPage() + { + navigationService.NavigateWithHierarchy(typeof(PagesPage)); + } + + [RelayCommand] + private void NavigateToDialogsPage() + { + navigationService.NavigateWithHierarchy(typeof(DialogsPage)); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/FontIconsPageViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/FontIconsPageViewModel.cs new file mode 100644 index 000000000..1673ad6c1 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/FontIconsPageViewModel.cs @@ -0,0 +1,70 @@ +using System.IO; +using System.Reflection; +using System.Text.Json; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.UI.Playground.Client.Models; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages.DesignGuidance; + +[UsedImplicitly] +public partial class FontIconsPageViewModel : ObservableObject +{ + [ObservableProperty] private List _icons = []; + [ObservableProperty] private List _filteredIcons = []; + [ObservableProperty] private FontIconData? _selectedIcon; + [ObservableProperty] private string _searchText = string.Empty; + + public FontIconsPageViewModel() + { + var jsonText = ReadIconData(); + Icons = JsonSerializer.Deserialize>(jsonText)! + .OrderBy(data => data.Name) + .ToList(); + + SelectedIcon = _icons.FirstOrDefault(); + } + + private static string ReadIconData() + { + const string resourceName = "RevitLookup.UI.Playground.Client.Models.FontIcons.json"; + + var assembly = Assembly.GetExecutingAssembly(); + using var stream = assembly.GetManifestResourceStream(resourceName)!; + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + partial void OnIconsChanged(List value) + { + FilteredIcons = value; + } + + async partial void OnSearchTextChanged(string value) + { + FilteredIcons = await Task.Run(() => + { + if (string.IsNullOrWhiteSpace(value)) + { + return Icons; + } + + var formattedText = value.Trim(); + var results = new List(); + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var setData in Icons) + { + if (setData.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + results.Add(setData); + } + } + + return results; + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/SymbolIconsPageViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/SymbolIconsPageViewModel.cs new file mode 100644 index 000000000..00d716fdb --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DesignGuidance/SymbolIconsPageViewModel.cs @@ -0,0 +1,65 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.UI.Playground.Client.Models; +using Wpf.Ui.Controls; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages.DesignGuidance; + +[UsedImplicitly] +public partial class SymbolIconsPageViewModel : ObservableObject +{ + [ObservableProperty] private List _icons = []; + [ObservableProperty] private List _filteredIcons = []; + [ObservableProperty] private SymbolIconData? _selectedIcon; + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private bool _useFilledIcons; + + public SymbolIconsPageViewModel() + { + var symbols = Enum.GetNames(typeof(SymbolRegular)); + Icons = symbols.Select(SymbolGlyph.Parse) + .Select(symbol => new SymbolIconData + { + Name = symbol.ToString(), + Icon = symbol, + Code = ((int) symbol).ToString("X4") + }) + .OrderBy(data => data.Name) + .ToList(); + + SelectedIcon = _icons.FirstOrDefault(); + } + + partial void OnIconsChanged(List value) + { + FilteredIcons = value; + } + + async partial void OnSearchTextChanged(string value) + { + FilteredIcons = await Task.Run(() => + { + if (string.IsNullOrWhiteSpace(value)) + { + return Icons; + } + + var formattedText = value.Trim(); + var results = new List(); + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var setData in Icons) + { + if (setData.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + results.Add(setData); + } + } + + return results; + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DialogsViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DialogsViewModel.cs new file mode 100644 index 000000000..cb8e12d2b --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/DialogsViewModel.cs @@ -0,0 +1,127 @@ +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.ObservableModels.Entries; +using RevitLookup.UI.Framework.Views.AboutProgram; +using RevitLookup.UI.Framework.Views.EditDialogs; +using RevitLookup.UI.Framework.Views.Tools; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages; + +[UsedImplicitly] +public sealed partial class DialogsViewModel(IServiceProvider serviceProvider) : ObservableObject +{ + [RelayCommand] + private async Task ShowOpenSourceDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + [RelayCommand] + private async Task ShowSearchElementsDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + [RelayCommand] + private async Task ShowModulesDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + [RelayCommand] + private async Task ShowParametersDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowParametersDialogAsync(); + } + + [RelayCommand] + private async Task ShowCategoriesDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowCategoriesDialogAsync(); + } + + [RelayCommand] + private async Task ShowForgeSchemaDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowForgeSchemaDialogAsync(); + } + + [RelayCommand] + private async Task ShowEditValueDialogAsync() + { + var faker = new Faker(); + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowAsync(faker.Lorem.Word(), faker.Lorem.Sentence(5), "Update the parameter"); + } + + [RelayCommand] + private async Task ShowCreateIniEntryDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowCreateDialogAsync(null); + } + + [RelayCommand] + private async Task ShowUpdateIniEntryDialogAsync() + { + var entry = new Faker() + .RuleFor(entry => entry.Category, faker => faker.Commerce.Product()) + .RuleFor(entry => entry.Property, faker => faker.Lorem.Word()) + .RuleFor(entry => entry.Value, faker => faker.Lorem.Word()); + + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowUpdateDialogAsync(entry); + } + + [RelayCommand] + private async Task ShowBoundingBoxVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("boundingBox"); + } + + [RelayCommand] + private async Task ShowFaceVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("face"); + } + + [RelayCommand] + private async Task ShowMeshVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("mesh"); + } + + [RelayCommand] + private async Task ShowPolylineVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("polyline"); + } + + [RelayCommand] + private async Task ShowSolidVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("solid"); + } + + [RelayCommand] + private async Task ShowXyzVisualizationDialogAsync() + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync("point"); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/PagesViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/PagesViewModel.cs new file mode 100644 index 000000000..b5027b2b3 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/PagesViewModel.cs @@ -0,0 +1,93 @@ +using System.Windows; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Views.AboutProgram; +using RevitLookup.UI.Framework.Views.Dashboard; +using RevitLookup.UI.Framework.Views.Decomposition; +using RevitLookup.UI.Framework.Views.Settings; +using RevitLookup.UI.Framework.Views.Tools; +using RevitLookup.UI.Playground.Client.Controls; + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages; + +[UsedImplicitly] +public sealed partial class PagesViewModel : ObservableObject +{ + [RelayCommand] + private void ShowDashboardPage() + { + var viewer = Host.CreateScope(); + viewer.SizeToContent = SizeToContent.Width; + viewer.Height = 850; + viewer.ShowPage(); + } + + [RelayCommand] + private void ShowDecompositionSummaryPage() + { + var viewer = Host.CreateScope(); + viewer.SizeToContent = SizeToContent.Manual; + viewer.Height = 500; + viewer.Width = 900; + viewer.RunService(service => + { + var faker = new Faker(); + + var strings = new List(); + for (var i = 0; i < 1000; i++) + { + strings.Add(faker.Lorem.Sentence(300)); + } + + service.VisualizeDecompositionAsync(strings); + }); + + viewer.ShowPage(); + } + + [RelayCommand] + private void ShowEventsSummaryPage() + { + var viewer = Host.CreateScope(); + viewer.SizeToContent = SizeToContent.Manual; + viewer.Height = 500; + viewer.Width = 900; + viewer.RunService(service => service.OnNavigatedToAsync()); + + viewer.Closing += (sender, _) => + { + var self = (PageViewer) sender!; + self.RunService(service => service.OnNavigatedFromAsync()); + }; + + viewer.ShowPage(); + } + + [RelayCommand] + private void ShowSettingsPage() + { + var viewer = Host.CreateScope(); + viewer.ShowPage(); + } + + [RelayCommand] + private void ShowAboutPage() + { + var viewer = Host.CreateScope(); + viewer.ShowPage(); + } + + [RelayCommand] + private void ShowRevitSettingsPage() + { + var viewer = Host.CreateScope(); + viewer.SizeToContent = SizeToContent.Manual; + viewer.Height = 850; + viewer.Width = 550; + viewer.ShowPage(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/WindowsViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/WindowsViewModel.cs new file mode 100644 index 000000000..dd2b067de --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/Pages/WindowsViewModel.cs @@ -0,0 +1,96 @@ +using System.Numerics; +using System.Reflection; +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Dashboard; +using RevitLookup.UI.Framework.Views.Decomposition; + +namespace RevitLookup.UI.Playground.Client.ViewModels.Pages; + +[UsedImplicitly] +public sealed partial class WindowsViewModel : ObservableObject +{ + [RelayCommand] + private void ShowRevitLookupWindow() + { + Host.GetService() + .Show(); + } + + [RelayCommand] + private void ShowEventsWindow() + { + Host.GetService() + .Show(); + } + + [RelayCommand] + private void ShowDecomposeColorsWindow() + { + var faker = new Faker(); + + var colors = new List(); + for (var i = 0; i < faker.Random.Int(1, 666); i++) + { + colors.Add(Color.FromArgb( + faker.Random.Byte(), + faker.Random.Byte(), + faker.Random.Byte(), + faker.Random.Byte() + )); + } + + Host.GetService() + .Decompose(colors) + .Show(); + } + + [RelayCommand] + private void ShowDecomposeTextWindow() + { + var faker = new Faker(); + + var strings = new List(); + for (var i = 0; i < faker.Random.Int(1, 666); i++) + { + strings.Add(faker.Lorem.Sentence(666)); + } + + Host.GetService() + .Decompose(strings) + .Show(); + } + + [RelayCommand] + private void ShowDecomposeTypesWindow() + { + var assembly = Assembly.GetExecutingAssembly(); + Host.GetService() + .Decompose(assembly.GetTypes()) + .Show(); + } + + [RelayCommand] + private void ShowDecomposeResolvedValuesWindow() + { + var faker = new Faker(); + + var vectors = new List(); + for (var i = 0; i < faker.Random.Int(1, 666); i++) + { + vectors.Add(new Vector3( + faker.Random.Float(), + faker.Random.Float(), + faker.Random.Float() + )); + } + + Host.GetService() + .Decompose(vectors) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/ViewModels/PlaygroundViewModel.cs b/source/RevitLookup.UI.Playground/Client/ViewModels/PlaygroundViewModel.cs new file mode 100644 index 000000000..120b026e0 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/ViewModels/PlaygroundViewModel.cs @@ -0,0 +1,42 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using RevitLookup.UI.Playground.Client.Views.Pages; +using RevitLookup.UI.Playground.Client.Views.Pages.DesignGuidance; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Client.ViewModels; + +[UsedImplicitly] +public sealed class PlaygroundViewModel : ObservableObject +{ + public List MenuItems { get; } = + [ + new NavigationViewItem("Home", SymbolRegular.Home24, typeof(DashboardPage)), + new NavigationViewItem + { + Content = "Design guidance", + Icon = new SymbolIcon(SymbolRegular.DesignIdeas24, 18), + MenuItemsSource = new object[] + { + new NavigationViewItem("Typography", SymbolRegular.TextFont24, typeof(TypographyPage)), + // new NavigationViewItem("Colors", SymbolRegular.Color24, typeof(DashboardPage)), + new NavigationViewItem("Segoe icons", SymbolRegular.Diversity24, typeof(FontIconsPage)), + new NavigationViewItem("Fluent icons", SymbolRegular.Diversity24, typeof(SymbolIconsPage)), + } + }, + // new NavigationViewItemSeparator(), + ]; + + public List FooterItems { get; } = + [ + new NavigationViewItem("Switch theme", SymbolRegular.DarkTheme24, null!) {Command = new RelayCommand(SwitchApplicationTheme)} + ]; + + private static void SwitchApplicationTheme() + { + var applicationTheme = ApplicationThemeManager.GetAppTheme(); + ApplicationThemeManager.Apply(applicationTheme == ApplicationTheme.Light ? ApplicationTheme.Dark : ApplicationTheme.Light); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml new file mode 100644 index 000000000..059e09e50 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml.cs new file mode 100644 index 000000000..38a8c40e0 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DashboardPage.xaml.cs @@ -0,0 +1,12 @@ +using RevitLookup.UI.Playground.Client.ViewModels.Pages; + +namespace RevitLookup.UI.Playground.Client.Views.Pages; + +public sealed partial class DashboardPage +{ + public DashboardPage(DashboardViewModel viewModel) + { + DataContext = viewModel; + InitializeComponent(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml new file mode 100644 index 000000000..1614213e5 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + How to get the font + + + + On Windows 11: There's nothing you need to do, the font comes with Windows. + + On Windows 10: Segoe Fluent Icons is not included by default on Windows 10. You can download it + + here + + . + + + + + How to use the font + + + + An icon with a 16-epx font size is the equivalent of a 16x16-epx icon, to make sizing and positioning more predictable. + For optimal appearance, use these specific sizes: 16, 20, 24, 32, 40, 48, and 64. Deviating from these font sizes could lead to less crisp or blurry outcomes. + + + + All glyphs in Segoe Fluent Icons have the same fixed width with a consistent height and left origin point, so + + layering + + and colorization effects can be achieved by drawing glyphs directly on top of each other. + + + + + XAML + + + + <ui:FontIcon Glyph="&#xEB51;" /> + + + + <ui:FontIcon Glyph="&#xEB51;" Foreground="#C72335" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml.cs new file mode 100644 index 000000000..1c7efda21 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/FontIconsPage.xaml.cs @@ -0,0 +1,37 @@ +using System.Windows; +using System.Windows.Input; +using RevitLookup.UI.Playground.Client.ViewModels.Pages.DesignGuidance; + +namespace RevitLookup.UI.Playground.Client.Views.Pages.DesignGuidance; + +public sealed partial class FontIconsPage +{ + static FontIconsPage() + { + CommandManager.RegisterClassCommandBinding(typeof(FontIconsPage), new CommandBinding(ApplicationCommands.Copy, OnCopyContentClicked)); + } + + public FontIconsPage(FontIconsPageViewModel viewModel) + { + InitializeComponent(); + DataContext = viewModel; + } + + private static void OnCopyContentClicked(object sender, RoutedEventArgs args) + { + var routedArgs = (ExecutedRoutedEventArgs) args; + var parameter = routedArgs.Parameter.ToString(); + + if (!string.IsNullOrEmpty(parameter)) + { + try + { + Clipboard.SetText(parameter); + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml new file mode 100644 index 000000000..e24200cc9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + How to get the font + + + + + Fluent UI System Icons is not included by default on Windows. You can download it + + here + + . + + + + + How to use the font + + + + An icon with a 16-epx font size is the equivalent of a 16x16-epx icon, to make sizing and positioning more predictable. + For optimal appearance, use these specific sizes: 16, 20, 24, 32, 40, 48, and 64. Deviating from these font sizes could lead to less crisp or blurry outcomes. + + + + All icons in Fluent Icons font have the same fixed width with a consistent height and left origin point, + so layering and colorization effects can be achieved by drawing glyphs directly on top of each other. + + + + + XAML + + + + <ui:SymbolIcon Symbol="Savings24" /> + + + + <ui:SymbolIcon Symbol="Savings24" Filled="True" /> + + + + <ui:SymbolIcon Symbol="Savings24" Foreground="#C72335" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml.cs new file mode 100644 index 000000000..b0c7adb47 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/SymbolIconsPage.xaml.cs @@ -0,0 +1,37 @@ +using System.Windows; +using System.Windows.Input; +using RevitLookup.UI.Playground.Client.ViewModels.Pages.DesignGuidance; + +namespace RevitLookup.UI.Playground.Client.Views.Pages.DesignGuidance; + +public sealed partial class SymbolIconsPage +{ + static SymbolIconsPage() + { + CommandManager.RegisterClassCommandBinding(typeof(SymbolIconsPage), new CommandBinding(ApplicationCommands.Copy, OnCopyContentClicked)); + } + + public SymbolIconsPage(SymbolIconsPageViewModel viewModel) + { + InitializeComponent(); + DataContext = viewModel; + } + + private static void OnCopyContentClicked(object sender, RoutedEventArgs args) + { + var routedArgs = (ExecutedRoutedEventArgs) args; + var parameter = routedArgs.Parameter.ToString(); + + if (!string.IsNullOrEmpty(parameter)) + { + try + { + Clipboard.SetText(parameter); + } + catch + { + // ignored + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml new file mode 100644 index 000000000..b8a780a33 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml.cs new file mode 100644 index 000000000..32993e129 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DesignGuidance/TypographyPage.xaml.cs @@ -0,0 +1,10 @@ +namespace RevitLookup.UI.Playground.Client.Views.Pages.DesignGuidance; + +public sealed partial class TypographyPage +{ + public TypographyPage() + { + DataContext = this; + InitializeComponent(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml new file mode 100644 index 000000000..39d5e782f --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml.cs new file mode 100644 index 000000000..6f4f5e0b7 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/DialogsPage.xaml.cs @@ -0,0 +1,16 @@ +using RevitLookup.UI.Playground.Client.ViewModels.Pages; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.UI.Playground.Client.Views.Pages; + +public sealed partial class DialogsPage : INavigableView +{ + public DialogsPage(DialogsViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + InitializeComponent(); + } + + public DialogsViewModel ViewModel { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml new file mode 100644 index 000000000..0df386830 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml.cs new file mode 100644 index 000000000..8da38926f --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/PagesPage.xaml.cs @@ -0,0 +1,16 @@ +using RevitLookup.UI.Playground.Client.ViewModels.Pages; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.UI.Playground.Client.Views.Pages; + +public sealed partial class PagesPage : INavigableView +{ + public PagesPage(PagesViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + InitializeComponent(); + } + + public PagesViewModel ViewModel { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml b/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml new file mode 100644 index 000000000..2622e7e78 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml.cs new file mode 100644 index 000000000..880646a3b --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/Pages/WindowsPage.xaml.cs @@ -0,0 +1,16 @@ +using RevitLookup.UI.Playground.Client.ViewModels.Pages; +using Wpf.Ui.Abstractions.Controls; + +namespace RevitLookup.UI.Playground.Client.Views.Pages; + +public sealed partial class WindowsPage : INavigableView +{ + public WindowsPage(WindowsViewModel viewModel) + { + ViewModel = viewModel; + DataContext = this; + InitializeComponent(); + } + + public WindowsViewModel ViewModel { get; } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml b/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml new file mode 100644 index 000000000..4bd5227a8 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml.cs b/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml.cs new file mode 100644 index 000000000..29b6b0218 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Client/Views/PlaygroundView.xaml.cs @@ -0,0 +1,53 @@ +using System.Windows; +using System.Windows.Automation.Peers; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Controls.Automation; +using RevitLookup.UI.Playground.Client.ViewModels; +using RevitLookup.UI.Playground.Client.Views.Pages; +using Wpf.Ui; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Client.Views; + +public sealed partial class PlaygroundView +{ + private readonly INavigationService _navigationService; + + public PlaygroundView( + PlaygroundViewModel viewModel, + INavigationService navigationService, + IContentDialogService dialogService, + ISnackbarService snackbarService, + IWindowIntercomService intercomService) + { + _navigationService = navigationService; + DataContext = viewModel; + InitializeComponent(); + + navigationService.SetNavigationControl(NavigationView); + dialogService.SetDialogHost(RootContentDialog); + snackbarService.SetSnackbarPresenter(SnackbarPresenter); + intercomService.SetHost(this); + + Loaded += (sender, _) => + { + var self = (PlaygroundView) sender; + self._navigationService.Navigate(typeof(DashboardPage)); + }; + } + + private void OnNavigationSelectionChanged(object sender, RoutedEventArgs e) + { + if (sender is not NavigationView navigationView) return; + + var onControlsPage = navigationView.SelectedItem?.TargetPageType != typeof(DashboardPage); + var showHeader = onControlsPage ? Visibility.Visible : Visibility.Collapsed; + + NavigationView.SetCurrentValue(NavigationView.HeaderVisibilityProperty, showHeader); + } + + protected override AutomationPeer OnCreateAutomationPeer() + { + return new NoAutomationWindowPeer(this); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Host.cs b/source/RevitLookup.UI.Playground/Host.cs new file mode 100644 index 000000000..0e9b0b3f9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Host.cs @@ -0,0 +1,87 @@ +using System.Windows; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.UI.Framework.Services; +using RevitLookup.UI.Framework.Services.Presentation; +using RevitLookup.UI.Playground.Client.Services; +using RevitLookup.UI.Playground.Mockups.Config; +using RevitLookup.UI.Playground.Mockups.Services.Appearance; +using RevitLookup.UI.Playground.Mockups.Services.Application; +using RevitLookup.UI.Playground.Mockups.Services.Settings; +using RevitLookup.UI.Playground.Mockups.Services.Summary; +using Wpf.Ui; +using Wpf.Ui.Abstractions; + +namespace RevitLookup.UI.Playground; + +/// +/// Provides a host for the application's services and manages their lifetimes. +/// +public static class Host +{ + private static readonly IServiceProvider ServiceProvider = RegisterServices(); + + private static ServiceProvider RegisterServices() + { + var services = new ServiceCollection(); + + services.AddLogging(builder => builder.AddSerilogConfiguration()); + + services.AddApplicationOptions(); + services.AddAssemblyOptions(); + services.AddFolderOptions(); + services.AddSerializerOptions(); + + //Frontend services + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + //MVVM services + services.RegisterViews(); + services.RegisterViewModels(); + + //Services + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddScoped(); + services.AddTransient(); + + return services.BuildServiceProvider(); + } + + /// + /// Gets a service of the specified type. + /// + /// The type of service object to get. + /// A service object of type T. + public static T GetService() where T : class + { + return ServiceProvider.GetRequiredService(); + } + + /// + /// Creates a window with the scope lifetime. + /// + /// The type of window to get. + /// A window of type T. + public static T CreateScope() where T : Window + { + var scopeFactory = ServiceProvider.GetRequiredService(); + var scope = scopeFactory.CreateScope(); + + var window = scope.ServiceProvider.GetRequiredService(); + window.Closed += (_, _) => scope.Dispose(); + + return window; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Config/ApplicationOptions.cs b/source/RevitLookup.UI.Playground/Mockups/Config/ApplicationOptions.cs new file mode 100644 index 000000000..6c4913bad --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Config/ApplicationOptions.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.Versioning; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using RevitLookup.Abstractions.Options; +using RevitLookup.Common.Utils; + +namespace RevitLookup.UI.Playground.Mockups.Config; + +public static class ApplicationOptions +{ + public static void AddApplicationOptions(this IServiceCollection services) + { + services.Configure(options => options.SuppressStatusMessages = true); + } + + public static void AddFolderOptions(this IServiceCollection services) + { + var rootPath = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName; + services.Configure(options => + { + options.RootFolder = rootPath; + options.ConfigFolder = Path.Combine(rootPath, "Config"); + options.DownloadsFolder = Path.Combine(rootPath, "Downloads"); + options.GeneralSettingsPath = Path.Combine(rootPath, "Config", "Settings.cfg"); + options.RenderSettingsPath = Path.Combine(rootPath, "Config", "RenderSettings.cfg"); + }); + } + + public static void AddAssemblyOptions(this IServiceCollection services) + { + var assembly = Assembly.GetExecutingAssembly(); + var assemblyLocation = assembly.Location; + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + var fileVersion = new Version(FileVersionInfo.GetVersionInfo(assemblyLocation).FileVersion!); + + var targetFrameworkAttribute = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true) + .Cast() + .First(); + + services.Configure(options => + { + options.Framework = targetFrameworkAttribute.FrameworkDisplayName ?? targetFrameworkAttribute.FrameworkName; + options.Version = new Version(fileVersion.Major, fileVersion.Minor, fileVersion.Build); + options.HasAdminAccess = assemblyLocation.StartsWith(appDataPath) || !AccessUtils.CheckWriteAccess(assemblyLocation); + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Config/LoggerConfigurator.cs b/source/RevitLookup.UI.Playground/Mockups/Config/LoggerConfigurator.cs new file mode 100644 index 000000000..34b1af26c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Config/LoggerConfigurator.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace RevitLookup.UI.Playground.Mockups.Config; + +public static class LoggerConfigurator +{ + private const string LogTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"; + + public static void AddSerilogConfiguration(this ILoggingBuilder builder) + { + var logger = CreateDefaultLogger(); + builder.AddSerilog(logger); + + AppDomain.CurrentDomain.UnhandledException += OnOnUnhandledException; + } + + private static Logger CreateDefaultLogger() + { + return new LoggerConfiguration() + .WriteTo.Console(LogEventLevel.Information, LogTemplate) + .WriteTo.Debug(LogEventLevel.Debug, LogTemplate) + .MinimumLevel.Debug() + .CreateLogger(); + } + + private static void OnOnUnhandledException(object sender, UnhandledExceptionEventArgs args) + { + var exception = (Exception) args.ExceptionObject; + var logger = Host.GetService>(); + logger.LogCritical(exception, "Domain unhandled exception"); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Config/SerializerOptions.cs b/source/RevitLookup.UI.Playground/Mockups/Config/SerializerOptions.cs new file mode 100644 index 000000000..e9a95c5fd --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Config/SerializerOptions.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.DependencyInjection; + +namespace RevitLookup.UI.Playground.Mockups.Config; + +public static class SerializerOptions +{ + /// + /// Add global JsonSerialization configuration/> + /// + public static void AddSerializerOptions(this IServiceCollection services) + { + services.Configure(options => + { +#if DEBUG + options.WriteIndented = true; +#endif + options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.Converters.Add(new JsonStringEnumConverter()); + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs new file mode 100644 index 000000000..f6cf3a8f5 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs @@ -0,0 +1,96 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.Common.Utils; +using RevitLookup.UI.Framework.Extensions; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.UI.Playground.Mockups.Core.Decomposition.Descriptors; + +public sealed class ColorMediaDescriptor : Descriptor, IDescriptorExtension, IContextMenuConnector +{ + private readonly Color _color; + + public ColorMediaDescriptor(Color color) + { + _color = color; + Name = $"RGB: {color.R} {color.B} {color.B}"; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("HEX", () => Variants.Value(ColorRepresentationUtils.ColorToHex(_color.GetDrawingColor()))); + manager.Register("HEX int", () => Variants.Value(ColorRepresentationUtils.ColorToHexInteger(_color.GetDrawingColor()))); + manager.Register("RGB", () => Variants.Value(ColorRepresentationUtils.ColorToRgb(_color.GetDrawingColor()))); + manager.Register("HSL", () => Variants.Value(ColorRepresentationUtils.ColorToHsl(_color.GetDrawingColor()))); + manager.Register("HSV", () => Variants.Value(ColorRepresentationUtils.ColorToHsv(_color.GetDrawingColor()))); + manager.Register("CMYK", () => Variants.Value(ColorRepresentationUtils.ColorToCmyk(_color.GetDrawingColor()))); + manager.Register("HSB", () => Variants.Value(ColorRepresentationUtils.ColorToHsb(_color.GetDrawingColor()))); + manager.Register("HSI", () => Variants.Value(ColorRepresentationUtils.ColorToHsi(_color.GetDrawingColor()))); + manager.Register("HWB", () => Variants.Value(ColorRepresentationUtils.ColorToHwb(_color.GetDrawingColor()))); + manager.Register("NCol", () => Variants.Value(ColorRepresentationUtils.ColorToNCol(_color.GetDrawingColor()))); + manager.Register("CIELAB", () => Variants.Value(ColorRepresentationUtils.ColorToCielab(_color.GetDrawingColor()))); + manager.Register("CIEXYZ", () => Variants.Value(ColorRepresentationUtils.ColorToCieXyz(_color.GetDrawingColor()))); + manager.Register("VEC4", () => Variants.Value(ColorRepresentationUtils.ColorToFloat(_color.GetDrawingColor()))); + manager.Register("Decimal", () => Variants.Value(ColorRepresentationUtils.ColorToDecimal(_color.GetDrawingColor()))); + manager.Register("Name", () => Variants.Value(ColorRepresentationUtils.GetColorName(_color.GetDrawingColor()))); + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("DeleteMenuItem") + .SetCommand(_color, DeleteElement) + .SetShortcut(Key.Delete); + + void DeleteElement(Color element) + { + var notificationService = serviceProvider.GetRequiredService(); + try + { + var summaryViewModel = serviceProvider.GetRequiredService(); + var placementTarget = (FrameworkElement) contextMenu.PlacementTarget; + summaryViewModel.RemoveItem(placementTarget.DataContext); + + notificationService.ShowSuccess("Success", $"Element successfully removed"); + } + catch (OperationCanceledException exception) + { + notificationService.ShowWarning("Warning", exception.Message); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + + logger.LogError(exception, "Color deletion error"); + notificationService.ShowError("Color deletion error", exception.Message); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/Vector3Descriptor.cs b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/Vector3Descriptor.cs new file mode 100644 index 000000000..bfd63a28c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/Descriptors/Vector3Descriptor.cs @@ -0,0 +1,43 @@ +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.UI.Playground.Mockups.Core.Decomposition.Descriptors; + +public sealed class Vector3Descriptor : Descriptor, IDescriptorResolver +{ + private readonly Vector3 _vector3; + + public Vector3Descriptor(Vector3 vector3) + { + _vector3 = vector3; + Name = $"{vector3.X} {vector3.Y} {vector3.Z}"; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Vector3.Equals) when parameters[0].ParameterType == typeof(Vector3) => ResolveVectorEquals, + nameof(Vector3.Equals) when parameters.Length == 1 => ResolveObjectEquals, + _ => null + }; + + IVariant ResolveVectorEquals() + { + return Variants.Value(_vector3.Equals(Vector3.Zero), $"Vector-vector comparison"); + } + + [SuppressMessage("ReSharper", "SuspiciousTypeConversion.Global")] + IVariant ResolveObjectEquals() + { + return Variants.Values(3) + .Add(_vector3.Equals(Vector3.Zero), $"Vector-vector comparison") + .Add(_vector3.Equals(true), "Vector-Boolean comparison") + .Add(_vector3.Equals(1), "Vector-Integer comparison") + .Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/DescriptorsMap.cs b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/DescriptorsMap.cs new file mode 100644 index 000000000..cda46a4d1 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Core/Decomposition/DescriptorsMap.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using System.Numerics; +using System.Windows.Media; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Descriptors; +using RevitLookup.UI.Playground.Mockups.Core.Decomposition.Descriptors; + +namespace RevitLookup.UI.Playground.Mockups.Core.Decomposition; + +public static class DescriptorsMap +{ + /// + /// Search for a descriptor by approximate or exact match + /// + /// + /// Exact search is necessary for the reflection engine, to add extensions and resolve conflicts when calling methods and properties. Type is not null

+ /// An approximate search is needed to describe the object, which is displayed to the user. Type is null + /// + public static Descriptor FindDescriptor(object? obj, Type? type) + { + return obj switch + { + bool value when type is null || type == typeof(bool) => new BooleanDescriptor(value), + string value when type is null || type == typeof(string) => new StringDescriptor(value), + Exception value when type is null || type == typeof(Exception) => new ExceptionDescriptor(value), + Color color when type is null || type == typeof(Color) => new ColorMediaDescriptor(color), + Vector3 value when type is null || type == typeof(Vector3) => new Vector3Descriptor(value), + IEnumerable value => new EnumerableDescriptor(value), + _ => new ObjectDescriptor(obj) + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Mappers/DecompositionResultMapper.cs b/source/RevitLookup.UI.Playground/Mockups/Mappers/DecompositionResultMapper.cs new file mode 100644 index 000000000..16c12e52d --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Mappers/DecompositionResultMapper.cs @@ -0,0 +1,12 @@ +using LookupEngine.Abstractions; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using Riok.Mapperly.Abstractions; + +namespace RevitLookup.UI.Playground.Mockups.Mappers; + +[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Source)] +public static partial class DecompositionResultMapper +{ + public static partial ObservableDecomposedObject Convert(DecomposedObject decomposedObject); + public static partial ObservableDecomposedMember Convert(DecomposedMember decomposedMember); +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Appearance/MockThemeWatcherService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Appearance/MockThemeWatcherService.cs new file mode 100644 index 000000000..9baad07a4 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Appearance/MockThemeWatcherService.cs @@ -0,0 +1,72 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Settings; +using Wpf.Ui.Appearance; + +namespace RevitLookup.UI.Playground.Mockups.Services.Appearance; + +public sealed class MockThemeWatcherService(ISettingsService settingsService) : IThemeWatcherService +{ + private readonly List _observedElements = []; + + public void Initialize() + { + } + + public void Watch() + { + var theme = settingsService.GeneralSettings.Theme; + ApplicationThemeManager.Apply(theme, settingsService.GeneralSettings.Background); + UpdateBackground(theme); + } + + public void Watch(FrameworkElement frameworkElement) + { + frameworkElement.Loaded += OnWatchedElementLoaded; + frameworkElement.Unloaded += OnWatchedElementUnloaded; + } + + public void Unwatch() + { + } + + private void OnWatchedElementLoaded(object sender, RoutedEventArgs e) + { + var element = (FrameworkElement) sender; + _observedElements.Add(element); + } + + private void OnWatchedElementUnloaded(object sender, RoutedEventArgs e) + { + var element = (FrameworkElement) sender; + _observedElements.Remove(element); + } + + private void UpdateBackground(ApplicationTheme theme) + { + foreach (var window in _observedElements.Select(Window.GetWindow).Distinct()) + { + WindowBackgroundManager.UpdateBackground(window, theme, settingsService.GeneralSettings.Background); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Application/MockRevitLookupUiService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Application/MockRevitLookupUiService.cs new file mode 100644 index 000000000..4524cfab9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Application/MockRevitLookupUiService.cs @@ -0,0 +1,115 @@ +using System.Collections; +using System.Windows; +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.UI.Framework.Views.Windows; +using Wpf.Ui; + +namespace RevitLookup.UI.Playground.Mockups.Services.Application; + +public sealed class MockRevitLookupUiService : IRevitLookupUiService +{ + private Window? _parent; + private readonly Task _activeTask = Task.CompletedTask; + private readonly IServiceScope _scope; + private readonly IVisualDecompositionService _decompositionService; + private readonly INavigationService _navigationService; + private readonly Window _host; + + public MockRevitLookupUiService(IServiceScopeFactory scopeFactory) + { + _scope = scopeFactory.CreateScope(); + + _host = _scope.ServiceProvider.GetRequiredService(); + _decompositionService = _scope.ServiceProvider.GetRequiredService(); + _navigationService = _scope.ServiceProvider.GetRequiredService(); + + _host.Closed += (_, _) => _scope.Dispose(); + } + + public ILookupServiceDependsStage Decompose(KnownDecompositionObject decompositionObject) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decompositionObject), TaskScheduler.FromCurrentSynchronizationContext()); + return this; + } + + public ILookupServiceDependsStage Decompose(object? obj) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(obj), TaskScheduler.FromCurrentSynchronizationContext()); + return this; + } + + public ILookupServiceDependsStage Decompose(IEnumerable objects) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(objects), TaskScheduler.FromCurrentSynchronizationContext()); + return this; + } + + public ILookupServiceDependsStage Decompose(ObservableDecomposedObject decomposedObject) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObject), TaskScheduler.FromCurrentSynchronizationContext()); + return this; + } + + public ILookupServiceDependsStage Decompose(List decomposedObjects) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObjects), TaskScheduler.FromCurrentSynchronizationContext()); + return this; + } + + public ILookupServiceShowStage DependsOn(Window parent) + { + _parent = parent; + return this; + } + + public ILookupServiceRunStage Show() where T : Page + { + _activeTask.ContinueWith(_ => + { + ShowHost(false); + _navigationService.Navigate(typeof(T)); + }, TaskScheduler.FromCurrentSynchronizationContext()); + + return this; + } + + public void RunService(Action handler) where T : class + { + _activeTask.ContinueWith(_ => InvokeService(handler), TaskScheduler.FromCurrentSynchronizationContext()); + } + + private void InvokeService(Action handler) where T : class + { + var service = _scope.ServiceProvider.GetRequiredService(); + handler.Invoke(service); + } + + private void ShowHost(bool modal) + { + if (_parent is null) + { + _host.WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + else + { + _host.WindowStartupLocation = WindowStartupLocation.Manual; + _host.Left = _parent.Left + 47; + _host.Top = _parent.Top + 49; + } + + if (modal) + { + _host.ShowDialog(); + } + else + { + _host.Show(); + _host.Focus(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSettingsService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSettingsService.cs new file mode 100644 index 000000000..a12212a1c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSettingsService.cs @@ -0,0 +1,184 @@ +using System.IO; +using System.Text.Json; +using System.Windows.Media; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using RevitLookup.Abstractions.Models.Settings; +using RevitLookup.Abstractions.Options; +using RevitLookup.Abstractions.Services.Settings; +using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Mockups.Services.Settings; + +public sealed class MockSettingsService( + IOptions foldersOptions, + IOptions jsonOptions, + ILogger logger) + : ISettingsService +{ + private GeneralSettings? _generalSettings; + private RenderSettings? _renderSettings; + + public GeneralSettings GeneralSettings => _generalSettings ?? throw new InvalidOperationException("Settings is not loaded."); + public RenderSettings RenderSettings => _renderSettings ?? throw new InvalidOperationException("Settings is not loaded."); + + public void SaveSettings() + { + SaveGeneralSettings(); + SaveRenderSettings(); + } + + public void LoadSettings() + { + LoadGeneralSettings(); + LoadRenderSettings(); + } + + private void SaveGeneralSettings() + { + var path = foldersOptions.Value.GeneralSettingsPath; + if (!File.Exists(path)) Directory.CreateDirectory(Path.GetDirectoryName(path)!); + + var json = JsonSerializer.Serialize(_generalSettings, jsonOptions.Value); + File.WriteAllText(path, json); + } + + private void SaveRenderSettings() + { + var path = foldersOptions.Value.RenderSettingsPath; + if (!File.Exists(path)) Directory.CreateDirectory(Path.GetDirectoryName(path)!); + + var json = JsonSerializer.Serialize(_renderSettings, jsonOptions.Value); + File.WriteAllText(path, json); + } + + private void LoadGeneralSettings() + { + var path = foldersOptions.Value.GeneralSettingsPath; + if (!File.Exists(path)) + { + ResetGeneralSettings(); + return; + } + + try + { + using var config = File.OpenRead(path); + _generalSettings = JsonSerializer.Deserialize(config, jsonOptions.Value); + } + catch (Exception exception) + { + logger.LogError(exception, "General settings loading error"); + } + } + + private void LoadRenderSettings() + { + var path = foldersOptions.Value.RenderSettingsPath; + if (!File.Exists(path)) + { + ResetRenderSettings(); + return; + } + + try + { + using var config = File.OpenRead(path); + _renderSettings = JsonSerializer.Deserialize(config, jsonOptions.Value); + } + catch (Exception exception) + { + logger.LogError(exception, "General settings loading error"); + } + } + + public void ResetGeneralSettings() + { + _generalSettings = new GeneralSettings + { + Theme = ApplicationTheme.Light, + Background = WindowBackdropType.None, + Transition = Transition.None, + IncludeStatic = true, + IncludeEvents = true, + UseHardwareRendering = true + }; + } + + public void ResetRenderSettings() + { + _renderSettings = new RenderSettings + { + BoundingBoxSettings = new BoundingBoxVisualizationSettings + { + Transparency = 60, + SurfaceColor = Colors.DodgerBlue, + EdgeColor = Color.FromArgb(255, 30, 81, 255), + AxisColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowEdge = true, + ShowAxis = true + }, + FaceSettings = new FaceVisualizationSettings + { + Transparency = 20, + Extrusion = 1, + MinExtrusion = 1, + SurfaceColor = Colors.DodgerBlue, + MeshColor = Color.FromArgb(255, 30, 81, 255), + NormalVectorColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowMeshGrid = true, + ShowNormalVector = true + }, + MeshSettings = new MeshVisualizationSettings + { + Transparency = 20, + Extrusion = 1, + MinExtrusion = 1, + SurfaceColor = Colors.DodgerBlue, + MeshColor = Color.FromArgb(255, 30, 81, 255), + NormalVectorColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowMeshGrid = true, + ShowNormalVector = true + }, + PolylineSettings = new PolylineVisualizationSettings + { + Transparency = 20, + Diameter = 2, + MinThickness = 0.1, + SurfaceColor = Colors.DodgerBlue, + CurveColor = Color.FromArgb(255, 30, 81, 255), + DirectionColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowCurve = true, + ShowDirection = true + }, + SolidSettings = new SolidVisualizationSettings + { + Transparency = 20, + Scale = 1, + FaceColor = Colors.DodgerBlue, + EdgeColor = Color.FromArgb(255, 30, 81, 255), + ShowFace = true, + ShowEdge = true + }, + XyzSettings = new XyzVisualizationSettings + { + Transparency = 0, + AxisLength = 6, + MinAxisLength = 0.1, + XColor = Color.FromArgb(255, 30, 227, 255), + YColor = Color.FromArgb(255, 30, 144, 255), + ZColor = Color.FromArgb(255, 30, 81, 255), + ShowPlane = true, + ShowXAxis = true, + ShowYAxis = true, + ShowZAxis = true + } + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSoftwareUpdateService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSoftwareUpdateService.cs new file mode 100644 index 000000000..dbb30e55d --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Settings/MockSoftwareUpdateService.cs @@ -0,0 +1,38 @@ +using Bogus; +using RevitLookup.Abstractions.Services.Settings; + +namespace RevitLookup.UI.Playground.Mockups.Services.Settings; + +public sealed class MockSoftwareUpdateService : ISoftwareUpdateService +{ + public string? NewVersion { get; private set; } + public string? ReleaseNotesUrl { get; private set; } + public string? LocalFilePath { get; private set; } + public DateTime? LatestCheckDate { get; private set; } + + public async Task CheckUpdatesAsync() + { + await Task.Delay(1000); + LatestCheckDate = DateTime.Now; + + var faker = new Faker(); + var factor = faker.Random.Int(0, 100); + if (factor < 20) throw new OperationCanceledException(); + if (factor < 50) return false; + + NewVersion = faker.System.Version().ToString(3); + ReleaseNotesUrl = "https://github.com/"; + LocalFilePath = faker.System.FilePath().OrNull(faker); + + return true; + } + + public async Task DownloadUpdate() + { + await Task.Delay(1000); + + var faker = new Faker(); + var factor = faker.Random.Int(0, 100); + if (factor < 60) throw new OperationCanceledException(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockDecompositionService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockDecompositionService.cs new file mode 100644 index 000000000..c2b228bf5 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockDecompositionService.cs @@ -0,0 +1,84 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using LookupEngine; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.UI.Playground.Mockups.Core.Decomposition; +using RevitLookup.UI.Playground.Mockups.Mappers; + +namespace RevitLookup.UI.Playground.Mockups.Services.Summary; + +[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] +[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] +public sealed class MockDecompositionService(ISettingsService settingsService) : IDecompositionService +{ + public async Task DecomposeAsync(object obj) + { + var options = CreateDecomposeMembersOptions(); + return await Task.Run(() => + { + var result = LookupComposer.Decompose(obj, options); + return DecompositionResultMapper.Convert(result); + }); + } + + public async Task> DecomposeAsync(IEnumerable objects) + { + var options = CreateDecomposeOptions(); + return await Task.Run(() => + { + var capacity = objects is ICollection collection ? collection.Count : 4; + var decomposedObjects = new List(capacity); + foreach (var obj in objects) + { + var decomposedObject = LookupComposer.DecomposeObject(obj, options); + decomposedObjects.Add(DecompositionResultMapper.Convert(decomposedObject)); + } + + return decomposedObjects; + }); + } + + public async Task> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject) + { + var options = CreateDecomposeMembersOptions(); + return await Task.Run(() => + { + var decomposedMembers = LookupComposer.DecomposeMembers(decomposedObject.RawValue, options); + var members = new List(decomposedMembers.Count); + + foreach (var decomposedMember in decomposedMembers) + { + members.Add(DecompositionResultMapper.Convert(decomposedMember)); + } + + return members; + }); + } + + private static DecomposeOptions CreateDecomposeOptions() + { + return new DecomposeOptions + { + EnableRedirection = true, + TypeResolver = DescriptorsMap.FindDescriptor + }; + } + + private DecomposeOptions CreateDecomposeMembersOptions() + { + return new DecomposeOptions + { + IncludeRoot = settingsService.GeneralSettings.IncludeRootHierarchy, + IncludeFields = settingsService.GeneralSettings.IncludeFields, + IncludeEvents = settingsService.GeneralSettings.IncludeEvents, + IncludeUnsupported = settingsService.GeneralSettings.IncludeUnsupported, + IncludePrivateMembers = settingsService.GeneralSettings.IncludePrivate, + IncludeStaticMembers = settingsService.GeneralSettings.IncludeStatic, + EnableExtensions = settingsService.GeneralSettings.IncludeExtensions, + EnableRedirection = true, + TypeResolver = DescriptorsMap.FindDescriptor + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockVisualDecompositionService.cs b/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockVisualDecompositionService.cs new file mode 100644 index 000000000..a34b1cdfd --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Services/Summary/MockVisualDecompositionService.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using LookupEngine.Abstractions.Configuration; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; + +namespace RevitLookup.UI.Playground.Mockups.Services.Summary; + +[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] +[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] +public sealed class MockVisualDecompositionService( + IWindowIntercomService intercomService, + INotificationService notificationService, + IDecompositionService decompositionService, + IDecompositionSummaryViewModel summaryViewModel) + : IVisualDecompositionService +{ + public async Task VisualizeDecompositionAsync(KnownDecompositionObject decompositionObject) + { + try + { + switch (decompositionObject) + { + case KnownDecompositionObject.Face: + case KnownDecompositionObject.Edge: + case KnownDecompositionObject.LinkedElement: + case KnownDecompositionObject.Point: + case KnownDecompositionObject.SubElement: + HideHost(); + await Task.Delay(1000); + break; + } + + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(new object[] {decompositionObject}); + } + catch (OperationCanceledException) + { + notificationService.ShowWarning("Operation cancelled", "Operation cancelled by user"); + } + catch (Exception exception) + { + notificationService.ShowError("Operation cancelled", exception); + } + finally + { + ShowHost(); + } + } + + public async Task VisualizeDecompositionAsync(object? obj) + { + var objects = obj switch + { + ObservableDecomposedValue {Descriptor: IDescriptorEnumerator} decomposedValue => (IEnumerable) decomposedValue.RawValue!, + ObservableDecomposedValue decomposedValue => new[] {decomposedValue.RawValue}, + _ => new[] {obj} + }; + + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(objects); + } + + public async Task VisualizeDecompositionAsync(IEnumerable objects) + { + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(objects); + } + + public async Task VisualizeDecompositionAsync(ObservableDecomposedObject decomposedObject) + { + summaryViewModel.DecomposedObjects = [decomposedObject]; + await Task.CompletedTask; + } + + public async Task VisualizeDecompositionAsync(List decomposedObjects) + { + summaryViewModel.DecomposedObjects = decomposedObjects; + await Task.CompletedTask; + } + + private void ShowHost() + { + var host = intercomService.GetHost(); + if (!host.IsLoaded) return; + + host.Visibility = Visibility.Visible; + } + + private void HideHost() + { + var host = intercomService.GetHost(); + if (!host.IsLoaded) return; + + host.Visibility = Visibility.Hidden; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml new file mode 100644 index 000000000..b989df0c9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs new file mode 100644 index 000000000..d25bea18e --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs @@ -0,0 +1,27 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.UI.Playground.Mockups.Styles.ComponentStyles.MembersGrid; + +///

+/// Data grid cell template selector +/// +public sealed class DataGridCellTemplateSelector : DataTemplateSelector +{ + public override DataTemplate? SelectTemplate(object? item, DependencyObject container) + { + if (item is null) return null; + + var member = (ObservableDecomposedMember) item; + var presenter = (FrameworkElement) container; + var templateName = member.Value.RawValue switch + { + Color => "SummaryMediaColorCellTemplate", + _ => "DefaultSummaryCellTemplate" + }; + + return (DataTemplate) presenter.FindResource(templateName); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml new file mode 100644 index 000000000..4b3612bf8 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml @@ -0,0 +1,47 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml new file mode 100644 index 000000000..cf4778144 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml @@ -0,0 +1,49 @@ + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs new file mode 100644 index 000000000..914261483 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs @@ -0,0 +1,44 @@ +using System.Windows; +using System.Windows.Controls; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.UI.Playground.Mockups.Styles.ComponentStyles.MembersGrid; + +/// +/// Data grid row style selector +/// +public sealed class DataGridRowStyleSelector : StyleSelector +{ + public override Style? SelectStyle(object item, DependencyObject container) + { + var member = (ObservableDecomposedMember) item; + var presenter = (FrameworkElement) container; + + var styleName = SelectByType(member.Value.RawValue) ?? + SelectByDescriptor(member.Value.Descriptor); + + return (Style) presenter.FindResource(styleName); + } + + private static string? SelectByType(object? value) + { + return value switch + { + Exception => "ExceptionDataGridRowStyle", + _ => null + }; + } + + private static string SelectByDescriptor(Descriptor? descriptor) + { + return descriptor switch + { + IDescriptorEnumerator {IsEmpty: false} => "HandledDataGridRowStyle", + IDescriptorEnumerator => "DefaultLookupDataGridRowStyle", + IDescriptorCollector => "HandledDataGridRowStyle", + _ => "DefaultLookupDataGridRowStyle" + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml new file mode 100644 index 000000000..e0137e872 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs new file mode 100644 index 000000000..b54aec947 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs @@ -0,0 +1,27 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.UI.Playground.Mockups.Styles.ComponentStyles.ObjectsTree; + +public sealed class TreeViewItemTemplateSelector : DataTemplateSelector +{ + /// + /// Tree view row style selector + /// + public override DataTemplate? SelectTemplate(object? item, DependencyObject container) + { + if (item is null) return null; + + var presenter = (FrameworkElement) container; + var decomposedObject = (ObservableDecomposedObject) item; + var templateName = decomposedObject.RawValue switch + { + Color => "SummaryMediaColorItemTemplate", + _ => "DefaultSummaryTreeItemTemplate" + }; + + return (DataTemplate) presenter.FindResource(templateName); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/Styles/Converters/ObjectColorConverter.cs b/source/RevitLookup.UI.Playground/Mockups/Styles/Converters/ObjectColorConverter.cs new file mode 100644 index 000000000..19a6a8126 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/Styles/Converters/ObjectColorConverter.cs @@ -0,0 +1,28 @@ +using System.Globalization; +using System.Windows.Data; +using System.Windows.Markup; +using System.Windows.Media; + +namespace RevitLookup.UI.Playground.Mockups.Styles.Converters; + +public sealed class ObjectColorConverter : MarkupExtension, IValueConverter +{ + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value switch + { + Color color => color, + _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) + }; + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockAboutViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockAboutViewModel.cs new file mode 100644 index 000000000..b5e34234c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockAboutViewModel.cs @@ -0,0 +1,132 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Runtime; +using System.Text; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using RevitLookup.Abstractions.Options; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.States; +using RevitLookup.Abstractions.ViewModels.AboutProgram; +using RevitLookup.UI.Framework.Views.AboutProgram; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.AboutProgram; + +[UsedImplicitly] +public sealed partial class MockAboutViewModel : ObservableObject, IAboutViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly ISoftwareUpdateService _updateService; + + [ObservableProperty] private SoftwareUpdateState _state = (SoftwareUpdateState) (-1); + [ObservableProperty] private Version _currentVersion; + [ObservableProperty] private string? _newVersion; + [ObservableProperty] private string? _releaseNotesUrl; + [ObservableProperty] private string? _latestCheckDate; + [ObservableProperty] private string? _errorMessage; + [ObservableProperty] private string _runtime; + + public MockAboutViewModel(IServiceProvider serviceProvider, ISoftwareUpdateService updateService, IOptions assemblyOptions) + { + _serviceProvider = serviceProvider; + _updateService = updateService; + + CurrentVersion = assemblyOptions.Value.Version; + Runtime = new StringBuilder() + .Append(assemblyOptions.Value.Framework) + .Append(' ') + .Append(Environment.Is64BitProcess ? "x64" : "x86") + .Append(" (") + .Append(GCSettings.IsServerGC ? "Server" : "Workstation") + .Append(" GC)") + .ToString(); + + LatestCheckDate = _updateService.LatestCheckDate?.ToString("yyyy.MM.dd HH:mm:ss"); + UpdateSoftwareState(); + } + + [RelayCommand] + private async Task CheckUpdatesAsync() + { + try + { + var result = await _updateService.CheckUpdatesAsync(); + + if (!result) + { + State = SoftwareUpdateState.UpToDate; + return; + } + + UpdateSoftwareState(); + } + catch + { + State = SoftwareUpdateState.Error; + ErrorMessage = new Faker().Lorem.Sentence(); + } + finally + { + LatestCheckDate = _updateService.LatestCheckDate?.ToString("yyyy.MM.dd HH:mm:ss"); + } + } + + [RelayCommand] + private async Task DownloadUpdateAsync() + { + try + { + await _updateService.DownloadUpdate(); + State = SoftwareUpdateState.ReadyToInstall; + } + catch + { + State = SoftwareUpdateState.Error; + ErrorMessage = new Faker().Lorem.Sentence(); + } + } + + [RelayCommand] + private async Task ShowSoftwareDialogAsync() + { + var dialog = _serviceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + private void UpdateSoftwareState() + { + if (_updateService.LocalFilePath is not null) + { + State = SoftwareUpdateState.ReadyToInstall; + return; + } + + if (_updateService.NewVersion is null) return; + + NewVersion = _updateService.NewVersion; + ReleaseNotesUrl = _updateService.ReleaseNotesUrl; + State = SoftwareUpdateState.ReadyToDownload; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockOpenSourceViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockOpenSourceViewModel.cs new file mode 100644 index 000000000..93a8e8a96 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/AboutProgram/MockOpenSourceViewModel.cs @@ -0,0 +1,97 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.Models.AboutProgram; +using RevitLookup.Abstractions.ViewModels.AboutProgram; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.AboutProgram; + +[UsedImplicitly] +public sealed class MockOpenSourceViewModel : ObservableObject, IOpenSourceViewModel +{ + public List Software { get; } = + [ + new() + { + SoftwareName = "CommunityToolkit.Mvvm", + SoftwareUri = "https://github.com/CommunityToolkit/dotnet", + LicenseName = "MIT License", + LicenseUri = "https://github.com/CommunityToolkit/dotnet/blob/main/License.md" + }, + new() + { + SoftwareName = "Microsoft.Extensions.Hosting", + SoftwareUri = "https://github.com/dotnet/runtime", + LicenseName = "MIT License", + LicenseUri = "https://github.com/dotnet/runtime/blob/main/LICENSE.TXT" + }, + new() + { + SoftwareName = "Nice3point.Revit.Api", + SoftwareUri = "https://github.com/Nice3point/RevitApi", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitApi/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Extensions", + SoftwareUri = "https://github.com/Nice3point/RevitExtensions", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitExtensions/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Templates", + SoftwareUri = "https://github.com/Nice3point/RevitTemplates", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitTemplates/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Toolkit", + SoftwareUri = "https://github.com/Nice3point/RevitToolkit", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitToolkit/blob/main/License.md" + }, + new() + { + SoftwareName = "PolySharp", + SoftwareUri = "https://github.com/Sergio0694/PolySharp", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Sergio0694/PolySharp/blob/main/LICENSE" + }, + new() + { + SoftwareName = "Serilog", + SoftwareUri = "https://github.com/serilog/serilog", + LicenseName = "Apache License 2.0", + LicenseUri = "https://github.com/serilog/serilog/blob/dev/LICENSE" + }, + new() + { + SoftwareName = "WPF-UI", + SoftwareUri = "https://github.com/lepoco/wpfui", + LicenseName = "MIT License", + LicenseUri = "https://github.com/lepoco/wpfui/blob/main/LICENSE" + } + ]; +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Dashboard/MockDashboardViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Dashboard/MockDashboardViewModel.cs new file mode 100644 index 000000000..2194da3ee --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Dashboard/MockDashboardViewModel.cs @@ -0,0 +1,406 @@ +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Models.UserInterface; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Dashboard; +using RevitLookup.UI.Framework.Views.Decomposition; +using RevitLookup.UI.Framework.Views.Tools; +using Wpf.Ui; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Dashboard; + +[UsedImplicitly] +public sealed partial class MockDashboardViewModel : IDashboardViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly INavigationService _navigationService; + private readonly INotificationService _notificationService; + private readonly IVisualDecompositionService _visualDecompositionService; + + public MockDashboardViewModel( + IServiceProvider serviceProvider, + INavigationService navigationService, + INotificationService notificationService, + IVisualDecompositionService visualDecompositionService) + { + _serviceProvider = serviceProvider; + _navigationService = navigationService; + _notificationService = notificationService; + _visualDecompositionService = visualDecompositionService; + + NavigationGroups = + [ + new NavigationCardGroup + { + GroupName = "Workspace", + Items = + [ + new NavigationCardItem + { + Title = "Active view", + Description = "Explore and analyze the model's visual representation", + Icon = SymbolRegular.Image24, + Command = NavigatePageCommand, + CommandParameter = "view" + }, + new NavigationCardItem + { + Title = "Active document", + Description = "Explore the open document, including its structure and data", + Icon = SymbolRegular.Document24, + Command = NavigatePageCommand, + CommandParameter = "document" + }, + new NavigationCardItem + { + Title = "Application", + Description = "Explore application-wide settings and global data", + Icon = SymbolRegular.Apps24, + Command = NavigatePageCommand, + CommandParameter = "application" + }, + new NavigationCardItem + { + Title = "UI application", + Description = "Explore an active session of the Revit user interface", + Icon = SymbolRegular.WindowApps24, + Command = NavigatePageCommand, + CommandParameter = "uiApplication" + }, + new NavigationCardItem + { + Title = "UI controlled application", + Description = "Explore the Revit UI customization methods and events", + Icon = SymbolRegular.SquareHintApps24, + Command = NavigatePageCommand, + CommandParameter = "uiControlledApplication" + }, + new NavigationCardItem + { + Title = "Database", + Description = "Explore the Revit model database and its elements", + Icon = SymbolRegular.Database24, + Command = NavigatePageCommand, + CommandParameter = "database" + }, + ] + }, + new NavigationCardGroup + { + GroupName = "Interaction", + Items = + [ + new NavigationCardItem + { + Title = "Selection", + Description = "Explore currently selected elements in the model", + Icon = SymbolRegular.SquareHint24, + Command = NavigatePageCommand, + CommandParameter = "selection" + }, + new NavigationCardItem + { + Title = "Linked element", + Description = "Select and explore an element linked from another model", + Icon = SymbolRegular.LinkSquare24, + Command = NavigatePageCommand, + CommandParameter = "linked" + }, + new NavigationCardItem + { + Title = "Face", + Description = "Select and explore a face of the element's geometry", + Icon = SymbolRegular.LayerDiagonal20, + Command = NavigatePageCommand, + CommandParameter = "face" + }, + new NavigationCardItem + { + Title = "Edge", + Description = "Select and explore the edge of the element's geometry", + Icon = SymbolRegular.Line24, + Command = NavigatePageCommand, + CommandParameter = "edge" + }, + new NavigationCardItem + { + Title = "Point", + Description = "Select and explore a specific location or coordinate", + Icon = SymbolRegular.Location24, + Command = NavigatePageCommand, + CommandParameter = "point" + }, + new NavigationCardItem + { + Title = "Sub-element", + Description = "Select and explore a sub-element of the selected element", + Icon = SymbolRegular.Subtitles24, + Command = NavigatePageCommand, + CommandParameter = "subElement" + }, + new NavigationCardItem + { + Title = "Dependent elements", + Description = "Explore child elements associated with the selection", + Icon = SymbolRegular.DataLine24, + Command = NavigatePageCommand, + CommandParameter = "dependents" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Maintenance", + Items = + [ + new NavigationCardItem + { + Title = "Component manager", + Description = "Explore low-level visual components in Revit", + Icon = SymbolRegular.SlideTextMultiple32, + Command = NavigatePageCommand, + CommandParameter = "components" + }, + new NavigationCardItem + { + Title = "Performance adviser", + Description = "Explore performance issues in the open document", + Icon = SymbolRegular.HeartPulse24, + Command = NavigatePageCommand, + CommandParameter = "performance" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Registry", + Items = + [ + new NavigationCardItem + { + Title = "Updaters", + Description = "Explore all registered updaters in the session", + Icon = SymbolRegular.Whiteboard24, + Command = NavigatePageCommand, + CommandParameter = "updaters" + }, + new NavigationCardItem + { + Title = "Schemas", + Description = "Explore Extensible Storage framework schemas", + Icon = SymbolRegular.Box24, + Command = NavigatePageCommand, + CommandParameter = "schemas" + }, + new NavigationCardItem + { + Title = "Services", + Description = "Explore services that extend Revit's functionality", + Icon = SymbolRegular.WeatherCloudy24, + Command = NavigatePageCommand, + CommandParameter = "services" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Units", + Items = + [ + new NavigationCardItem + { + Title = "BuiltIn parameters", + Description = "Explore predefined parameters available in Revit", + Icon = SymbolRegular.LeafOne24, + Command = OpenDialogCommand, + CommandParameter = "parameters" + }, + new NavigationCardItem + { + Title = "BuiltIn categories", + Description = "Explore predefined categories available in Revit", + Icon = SymbolRegular.LeafTwo24, + Command = OpenDialogCommand, + CommandParameter = "categories" + }, + new NavigationCardItem + { + Title = "Forge schema", + Description = "Explore Forge schema definitions used in Revit", + Icon = SymbolRegular.LeafThree24, + Command = OpenDialogCommand, + CommandParameter = "forge" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Tools", + Items = + [ + new NavigationCardItem + { + Title = "Search elements", + Description = "Search for specific elements in the model", + Icon = SymbolRegular.SlideSearch24, + Command = OpenDialogCommand, + CommandParameter = "search" + }, + new NavigationCardItem + { + Title = "Event monitor", + Description = "Monitor all incoming events in a Revit session", + Icon = SymbolRegular.DesktopPulse24, + Command = NavigatePageCommand, + CommandParameter = "events" + }, + new NavigationCardItem + { + Title = "Revit settings", + Description = "Inspect configuration and Revit settings available in the application", + Icon = SymbolRegular.LauncherSettings24, + Command = NavigatePageCommand, + CommandParameter = "revitSettings" + }, + new NavigationCardItem + { + Title = "Modules", + Description = "Inspect the dynamic link libraries (DLLs) that Revit uses", + Icon = SymbolRegular.BroadActivityFeed24, + Command = OpenDialogCommand, + CommandParameter = "modules" + } + ] + } + ]; + } + + public List NavigationGroups { get; } + + [RelayCommand] + private async Task NavigatePage(string? parameter) + { + switch (parameter) + { + case "view": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.View); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "document": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Document); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "application": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Application); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "uiApplication": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UiApplication); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "uiControlledApplication": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UiControlledApplication); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "database": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Database); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "dependents": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.DependentElements); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "selection": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Selection); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "linked": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.LinkedElement); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "face": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Face); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "edge": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Edge); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "point": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Point); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "subElement": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.SubElement); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "components": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.ComponentManager); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "performance": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.PerformanceAdviser); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "updaters": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UpdaterRegistry); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "services": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Services); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "schemas": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Schemas); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "events": + _navigationService.Navigate(typeof(EventsSummaryPage)); + break; + case "revitSettings": + _navigationService.NavigateWithHierarchy(typeof(RevitSettingsPage)); + break; + default: + throw new ArgumentOutOfRangeException(nameof(parameter), parameter); + } + } + + [RelayCommand] + private async Task OpenDialog(string parameter) + { + try + { + switch (parameter) + { + case "parameters": + var unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowParametersDialogAsync(); + return; + case "categories": + unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowCategoriesDialogAsync(); + return; + case "forge": + unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowForgeSchemaDialogAsync(); + return; + case "search": + var searchDialog = _serviceProvider.GetRequiredService(); + await searchDialog.ShowAsync(); + return; + case "modules": + var modulesDialog = _serviceProvider.GetRequiredService(); + await modulesDialog.ShowAsync(); + return; + } + } + catch (Exception exception) + { + _notificationService.ShowError("Failed to open dialog", exception); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockDecompositionSummaryViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockDecompositionSummaryViewModel.cs new file mode 100644 index 000000000..edb1f3c6f --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockDecompositionSummaryViewModel.cs @@ -0,0 +1,216 @@ +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using LookupEngine; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Decomposition; +using RevitLookup.UI.Playground.Mockups.Core.Decomposition; +using RevitLookup.UI.Playground.Mockups.Mappers; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Decomposition; + +[UsedImplicitly] +public sealed partial class MockDecompositionSummaryViewModel( + ISettingsService settingsService, + IWindowIntercomService intercomService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IDecompositionSummaryViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private ObservableDecomposedObject? _selectedDecomposedObject; + [ObservableProperty] private List _decomposedObjects = []; + [ObservableProperty] private ObservableCollection _filteredDecomposedObjects = []; + + public void Navigate(object? value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(ObservableDecomposedObject value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(List values) + { + Host.GetService() + .Decompose(values) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public async Task RefreshMembersAsync() + { + foreach (var decomposedObject in DecomposedObjects) + { + decomposedObject.Members.Clear(); + } + + try + { + await FetchMembersAsync(SelectedDecomposedObject); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + public void RemoveItem(object target) + { + switch (target) + { + case ObservableDecomposedObject decomposedObject: + for (var i = FilteredDecomposedObjects.Count - 1; i >= 0; i--) + { + var groupToRemove = FilteredDecomposedObjects[i]; + if (!groupToRemove.GroupItems.Remove(decomposedObject)) continue; + + if (groupToRemove.GroupItems.Count == 0) + { + //Remove the empty group + FilteredDecomposedObjects.Remove(groupToRemove); + } + } + + if (DecomposedObjects.Remove(decomposedObject)) + { + if (DecomposedObjects.Count == 0) + { + //Notify UI to update placeholders + OnPropertyChanged(nameof(DecomposedObjects)); + } + } + + break; + case ObservableDecomposedMember: + //Do nothing ?? + break; + } + } + + partial void OnDecomposedObjectsChanged(List value) + { + OnSearchTextChanged(SearchText); + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredDecomposedObjects = ApplyGrouping(DecomposedObjects); + return; + } + + FilteredDecomposedObjects = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var item in DecomposedObjects) + { + if (item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(item); + } + } + + return ApplyGrouping(searchResults); + }); + + if (FilteredDecomposedObjects.Count == 0) + { + SelectedDecomposedObject = null; + } + } + catch + { + // ignored + } + } + + async partial void OnSelectedDecomposedObjectChanged(ObservableDecomposedObject? value) + { + try + { + await FetchMembersAsync(value); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + private async Task FetchMembersAsync(ObservableDecomposedObject? value) + { + if (value is null) return; + if (value.Members.Count > 0) return; + + value.Members = await DecomposeMembersAsync(value); + } + + [SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] + private async Task> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject) + { + var options = new DecomposeOptions + { + IncludeRoot = settingsService.GeneralSettings.IncludeRootHierarchy, + IncludeFields = settingsService.GeneralSettings.IncludeFields, + IncludeEvents = settingsService.GeneralSettings.IncludeEvents, + IncludeUnsupported = settingsService.GeneralSettings.IncludeUnsupported, + IncludePrivateMembers = settingsService.GeneralSettings.IncludePrivate, + IncludeStaticMembers = settingsService.GeneralSettings.IncludeStatic, + EnableExtensions = settingsService.GeneralSettings.IncludeExtensions, + EnableRedirection = true, + TypeResolver = DescriptorsMap.FindDescriptor + }; + + return await Task.Run(() => + { + var decomposedMembers = LookupComposer.DecomposeMembers(decomposedObject.RawValue, options); + var members = new List(decomposedMembers.Count); + + foreach (var decomposedMember in decomposedMembers) + { + members.Add(DecompositionResultMapper.Convert(decomposedMember)); + } + + return members; + }); + } + + private ObservableCollection ApplyGrouping(List objects) + { + return objects + .OrderBy(data => data.TypeName) + .ThenBy(data => data.Name) + .GroupBy(data => data.TypeName) + .Select(group => new ObservableDecomposedObjectsGroup + { + GroupName = group.Key, + GroupItems = group.ToObservableCollection() + }) + .ToObservableCollection(); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockEventsSummaryViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockEventsSummaryViewModel.cs new file mode 100644 index 000000000..559ccd30b --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Decomposition/MockEventsSummaryViewModel.cs @@ -0,0 +1,187 @@ +using System.Collections.ObjectModel; +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Decomposition; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Decomposition; + +[UsedImplicitly] +public sealed partial class MockEventsSummaryViewModel( + IWindowIntercomService intercomService, + INotificationService notificationService, + IDecompositionService decompositionService, + ILogger logger) + : ObservableObject, IEventsSummaryViewModel +{ + private CancellationTokenSource? _cancellationTokenSource; + + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private ObservableDecomposedObject? _selectedDecomposedObject; + [ObservableProperty] private List _decomposedObjects = []; + [ObservableProperty] private ObservableCollection _filteredDecomposedObjects = []; + + public void Navigate(object? value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(ObservableDecomposedObject value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(List values) + { + Host.GetService() + .Decompose(values) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public async Task RefreshMembersAsync() + { + foreach (var decomposedObject in DecomposedObjects) + { + decomposedObject.Members.Clear(); + } + + try + { + await FetchMembersAsync(SelectedDecomposedObject); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + public async Task OnNavigatedToAsync() + { + _cancellationTokenSource = new CancellationTokenSource(); + + var faker = new Faker(); + var cancellationToken = _cancellationTokenSource.Token; + while (!cancellationToken.IsCancellationRequested) + { + var decomposedObject = await GenerateRandomObjectAsync(faker); + DecomposedObjects.Insert(0, decomposedObject); + + if (SearchText == string.Empty) FilteredDecomposedObjects.Insert(0, decomposedObject); + else OnSearchTextChanged(SearchText); + + await Task.Delay(1000, cancellationToken); + } + } + + public Task OnNavigatedFromAsync() + { + if (_cancellationTokenSource is null) return Task.CompletedTask; + + _cancellationTokenSource.Cancel(); + _cancellationTokenSource.Dispose(); + _cancellationTokenSource = null; + + return Task.CompletedTask; + } + + partial void OnDecomposedObjectsChanged(List value) + { + OnSearchTextChanged(SearchText); + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredDecomposedObjects = DecomposedObjects.ToObservableCollection(); + return; + } + + FilteredDecomposedObjects = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var item in DecomposedObjects) + { + if (item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(item); + } + } + + return searchResults.ToObservableCollection(); + }); + + if (FilteredDecomposedObjects.Count == 0) + { + SelectedDecomposedObject = null; + } + } + catch + { + // ignored + } + } + + async partial void OnSelectedDecomposedObjectChanged(ObservableDecomposedObject? value) + { + try + { + await FetchMembersAsync(value); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + private async Task FetchMembersAsync(ObservableDecomposedObject? decomposedObject) + { + if (decomposedObject is null) return; + if (decomposedObject.Members.Count > 0) return; + + decomposedObject.Members = await decompositionService.DecomposeMembersAsync(decomposedObject); + } + + private async Task GenerateRandomObjectAsync(Faker faker) + { + object item = faker.Random.Int(0, 100) switch + { + < 10 => faker.Random.Int(0, 100), + < 20 => faker.Random.Bool(), + < 30 => faker.Random.Uuid(), + < 40 => faker.Random.Hexadecimal(), + < 50 => faker.Date.Future(), + < 60 => faker.Internet.Url(), + < 70 => faker.Internet.Email(), + < 80 => Color.FromArgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()), + < 90 => faker.Random.Double(0, 100), + _ => faker.Lorem.Word() + }; + + return await decompositionService.DecomposeAsync(item); + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Settings/MockSettingsViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Settings/MockSettingsViewModel.cs new file mode 100644 index 000000000..c00f6e7d0 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Settings/MockSettingsViewModel.cs @@ -0,0 +1,192 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Interop; +using System.Windows.Media; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Settings; +using RevitLookup.UI.Framework.Views.Settings; +using RevitLookup.UI.Framework.Views.Windows; +using Wpf.Ui; +using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Settings; + +[UsedImplicitly] +public sealed partial class MockSettingsViewModel : ObservableObject, ISettingsViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly INavigationService _navigationService; + private readonly INotificationService _notificationService; + private readonly ISettingsService _settingsService; + private readonly IThemeWatcherService _themeWatcherService; + private readonly IWindowIntercomService _intercomService; + private readonly bool _initialized; + + [ObservableProperty] private ApplicationTheme _theme; + [ObservableProperty] private WindowBackdropType _background; + + [ObservableProperty] private bool _useTransition; + [ObservableProperty] private bool _useHardwareRendering; + [ObservableProperty] private bool _useSizeRestoring; + [ObservableProperty] private bool _useModifyTab; + + public MockSettingsViewModel( + IServiceProvider serviceProvider, + INavigationService navigationService, + INotificationService notificationService, + ISettingsService settingsService, + IThemeWatcherService themeWatcherService, + IWindowIntercomService intercomService) + { + _serviceProvider = serviceProvider; + _navigationService = navigationService; + _notificationService = notificationService; + _settingsService = settingsService; + _themeWatcherService = themeWatcherService; + _intercomService = intercomService; + + ApplySettings(); + _initialized = true; + } + + public List Themes { get; } = + [ + ApplicationTheme.Auto, + ApplicationTheme.Light, + ApplicationTheme.Dark, + ApplicationTheme.HighContrast + ]; + + public List BackgroundEffects { get; } = + [ + WindowBackdropType.None, + WindowBackdropType.Acrylic, + WindowBackdropType.Tabbed, + WindowBackdropType.Mica + ]; + + [RelayCommand] + private async Task ResetSettings() + { + try + { + var dialog = _serviceProvider.GetRequiredService(); + var result = await dialog.ShowAsync(); + if (result != ContentDialogResult.Primary) return; + + if (dialog.CanResetGeneralSettings) + { + _settingsService.ResetGeneralSettings(); + } + + if (dialog.CanResetRenderSettings) + { + _settingsService.ResetRenderSettings(); + } + + ApplySettings(); + _notificationService.ShowSuccess("Reset settings", "Settings successfully reset to default"); + } + catch (Exception exception) + { + _notificationService.ShowError("Reset settings error", exception); + } + } + + partial void OnThemeChanged(ApplicationTheme value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.Theme = value; + _themeWatcherService.Watch(); + } + + partial void OnBackgroundChanged(WindowBackdropType value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.Background = value; + WindowBackgroundManager.UpdateBackground(_intercomService.GetHost(), _settingsService.GeneralSettings.Theme, value); + } + + partial void OnUseTransitionChanged(bool value) + { + if (!_initialized) return; + + var navigationControl = _navigationService.GetNavigationControl(); + var transition = _settingsService.GeneralSettings.Transition = value + ? (Transition) NavigationView.TransitionProperty.DefaultMetadata.DefaultValue + : Transition.None; + + _settingsService.GeneralSettings.Transition = transition; + navigationControl.Transition = transition; + } + + partial void OnUseHardwareRenderingChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseHardwareRendering = value; + RenderOptions.ProcessRenderMode = value ? RenderMode.Default : RenderMode.SoftwareOnly; + } + + partial void OnUseSizeRestoringChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseSizeRestoring = value; + if (_intercomService.GetHost() is not RevitLookupView lookupView) return; + + if (value) + { + lookupView.EnableSizeTracking(); + } + else + { + lookupView.DisableSizeTracking(); + } + } + + partial void OnUseModifyTabChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseModifyTab = value; + } + + private void ApplySettings() + { + Theme = _settingsService.GeneralSettings.Theme; + Background = _settingsService.GeneralSettings.Background; + UseTransition = _settingsService.GeneralSettings.Transition != Transition.None; + UseHardwareRendering = _settingsService.GeneralSettings.UseHardwareRendering; + UseSizeRestoring = _settingsService.GeneralSettings.UseSizeRestoring; + UseModifyTab = _settingsService.GeneralSettings.UseModifyTab; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockModulesViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockModulesViewModel.cs new file mode 100644 index 000000000..e5592fd5c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockModulesViewModel.cs @@ -0,0 +1,102 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + + +using System.Runtime.Loader; +using CommunityToolkit.Mvvm.ComponentModel; +using RevitLookup.Abstractions.Models.Tools; +using RevitLookup.Abstractions.ViewModels.Tools; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Tools; + +public sealed partial class MockModulesViewModel : ObservableObject, IModulesViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private List _modules = []; + [ObservableProperty] private List _filteredModules = []; + + public MockModulesViewModel() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + Modules = new List(assemblies.Length); + + for (var i = 0; i < assemblies.Length; i++) + { + var assembly = assemblies[i]; + var assemblyName = assembly.GetName(); + var module = new ModuleInfo + { + Name = assemblyName.Name ?? string.Empty, + Path = assembly.IsDynamic ? string.Empty : assembly.Location, + Order = i + 1, + Version = assemblyName.Version is null ? string.Empty : assemblyName.Version.ToString(), +#if NETCOREAPP + Container = AssemblyLoadContext.GetLoadContext(assembly)?.Name ?? string.Empty +#else + Container = AppDomain.CurrentDomain.FriendlyName +#endif + }; + + Modules.Add(module); + } + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredModules = Modules; + return; + } + + FilteredModules = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var module in Modules) + { + if (module.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + module.Path.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + module.Version.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(module); + } + } + + return searchResults; + }); + } + catch + { + // ignored + } + } + + partial void OnModulesChanged(List value) + { + FilteredModules = value; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockRevitSettingsViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockRevitSettingsViewModel.cs new file mode 100644 index 000000000..4095b6db1 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockRevitSettingsViewModel.cs @@ -0,0 +1,214 @@ +using System.Collections.ObjectModel; +using System.Linq.Expressions; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using JetBrains.Annotations; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.ObservableModels.Entries; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Tools; +using RevitLookup.Common.Tools; +using RevitLookup.UI.Framework.Views.EditDialogs; +using Wpf.Ui.Controls; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class MockRevitSettingsViewModel( + IServiceProvider serviceProvider, + INotificationService notificationService) + : ObservableObject, IRevitSettingsViewModel +{ + private TaskNotifier>? _initializationTask; + + [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ClearFiltersCommand))] private bool _filtered; + [ObservableProperty] private string _categoryFilter = string.Empty; + [ObservableProperty] private string _propertyFilter = string.Empty; + [ObservableProperty] private string _valueFilter = string.Empty; + [ObservableProperty] private bool _showUserSettingsFilter; + [ObservableProperty] private ObservableIniEntry? _selectedEntry; + + [ObservableProperty] private List _entries = []; + [ObservableProperty] private ObservableCollection _filteredEntries = []; + + public Task>? InitializationTask + { + get => _initializationTask!; + private set => SetPropertyAndNotifyOnCompletion(ref _initializationTask, value); + } + + public async Task InitializeAsync() + { + InitializationTask = Task.Run(async () => + { + await Task.Delay(1000); + return new Faker() + .RuleFor(entry => entry.Property, faker => faker.Internet.DomainName()) + .RuleFor(entry => entry.Value, faker => faker.Internet.UrlRootedPath()) + .RuleFor(entry => entry.DefaultValue, faker => faker.Internet.UrlRootedPath().OrNull(faker, 0.3f)) + .RuleFor(entry => entry.Category, faker => faker.Company.CompanyName("{{name.lastName}}")) + .RuleFor(entry => entry.IsActive, faker => faker.Random.Bool()) + .Generate(10000); + }); + + Entries = await InitializationTask; + } + + [RelayCommand] + private async Task CreateEntry() + { + var dialog = serviceProvider.GetRequiredService(); + var result = await dialog.ShowCreateDialogAsync(SelectedEntry); + if (result == ContentDialogResult.Primary) + { + if (string.IsNullOrWhiteSpace(dialog.Entry.Category)) return; + if (string.IsNullOrWhiteSpace(dialog.Entry.Property)) return; + + Entries.Add(dialog.Entry); + FilteredEntries.Add(dialog.Entry); + } + } + + [RelayCommand] + private void ActivateEntry(ObservableIniEntry entry) + { + //Saving + } + + [RelayCommand] + private void DeleteEntry(ObservableIniEntry entry) + { + Entries.Remove(entry); + FilteredEntries.Remove(entry); + } + + [RelayCommand] + private void RestoreDefault(ObservableIniEntry entry) + { + entry.Value = entry.DefaultValue ?? string.Empty; + } + + [RelayCommand] + private void ShowHelp() + { + ProcessTasks.StartShell($"https://help.autodesk.com/view/RVT/{DateTime.Today.Year}/ENU/?guid=GUID-9ECD669E-81D3-43E5-9970-9FA1C38E8507"); + } + + [RelayCommand] + private void OpenSettings() + { + notificationService.ShowSuccess("Settings", "Successfully opened"); + } + + [RelayCommand(CanExecute = nameof(CanClearFiltersExecute))] + private void ClearFilters() + { + CategoryFilter = string.Empty; + PropertyFilter = string.Empty; + ValueFilter = string.Empty; + ShowUserSettingsFilter = false; + + ApplyFilters(); + } + + partial void OnEntriesChanged(List value) + { + ApplyFilters(); + } + + partial void OnCategoryFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnPropertyFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnValueFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnShowUserSettingsFilterChanged(bool value) + { + ApplyFilters(); + } + + public async Task UpdateEntryAsync() + { + if (SelectedEntry is null) return; + + var editingValue = SelectedEntry.Clone(); + var dialog = serviceProvider.GetRequiredService(); + var result = await dialog.ShowUpdateDialogAsync(editingValue); + if (result == ContentDialogResult.Primary) UpdateEntry(editingValue); + } + + private void UpdateEntry(ObservableIniEntry entry) + { + if (SelectedEntry is null) return; + + var forceRefresh = SelectedEntry.Category != entry.Category || SelectedEntry.Property != entry.Property; + + SelectedEntry.Category = entry.Category; + SelectedEntry.Property = entry.Property; + SelectedEntry.Value = entry.Value; + SelectedEntry.IsActive = true; + + if (forceRefresh) + { + ApplyFilters(); + } + } + + private void ApplyFilters() + { + var expressions = new List>>(4); + + if (!string.IsNullOrWhiteSpace(CategoryFilter)) + { + expressions.Add(entry => entry.Category.Contains((string) CategoryFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (!string.IsNullOrWhiteSpace(PropertyFilter)) + { + expressions.Add(entry => entry.Property.Contains((string) PropertyFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (!string.IsNullOrWhiteSpace(ValueFilter)) + { + expressions.Add(entry => entry.Value.Contains((string) ValueFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (ShowUserSettingsFilter) + { + expressions.Add(entry => entry.IsActive); + } + + if (expressions.Count == 0) + { + FilteredEntries = new ObservableCollection(Entries); + Filtered = false; + } + else + { + IEnumerable filtered = Entries; + + foreach (var expression in expressions) + { + filtered = filtered.Where(expression.Compile()); + } + + FilteredEntries = new ObservableCollection(filtered.ToList()); + Filtered = true; + } + } + + private bool CanClearFiltersExecute() + { + return Filtered; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockSearchElementsViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockSearchElementsViewModel.cs new file mode 100644 index 000000000..cfa611e06 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockSearchElementsViewModel.cs @@ -0,0 +1,31 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Tools; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class MockSearchElementsViewModel( + INotificationService notificationService, + IVisualDecompositionService decompositionService) + : ObservableObject, ISearchElementsViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + + public async Task SearchElementsAsync() + { + var result = SearchText != string.Empty; + if (result) + { + await decompositionService.VisualizeDecompositionAsync((object) SearchText); + } + else + { + notificationService.ShowWarning("Search elements", "There are no elements found for your request"); + } + + return result; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockUnitsViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockUnitsViewModel.cs new file mode 100644 index 000000000..f4a66ce7a --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Tools/MockUnitsViewModel.cs @@ -0,0 +1,109 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.Models.Tools; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.ViewModels.Tools; +#if NETFRAMEWORK +using RevitLookup.UI.Framework.Extensions; +#endif + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class MockUnitsViewModel(IVisualDecompositionService decompositionService) : ObservableObject, IUnitsViewModel +{ + [ObservableProperty] private List _units = []; + [ObservableProperty] private List _filteredUnits = []; + [ObservableProperty] private string _searchText = string.Empty; + + public void InitializeParameters() + { + Units = new Faker() + .RuleFor(info => info.Unit, faker => faker.Lorem.Sentence()) + .RuleFor(info => info.Label, faker => faker.Lorem.Word()) + .RuleFor(info => info.Value, faker => faker.Lorem.Word()) + .Generate(20); + } + + public void InitializeCategories() + { + Units = new Faker() + .RuleFor(info => info.Unit, faker => faker.Lorem.Sentence()) + .RuleFor(info => info.Label, faker => faker.Lorem.Word()) + .RuleFor(info => info.Value, faker => faker.Lorem.Word()) + .Generate(200); + } + + public void InitializeForgeSchema() + { + Units = new Faker() + .RuleFor(info => info.Unit, faker => faker.Lorem.Sentence()) + .RuleFor(info => info.Label, faker => faker.Lorem.Word()) + .RuleFor(info => info.Value, faker => faker.Lorem.Word()) + .RuleFor(info => info.Class, faker => faker.Lorem.Sentence()) + .Generate(2000); + } + + public async Task DecomposeAsync(UnitInfo unitInfo) + { + await decompositionService.VisualizeDecompositionAsync(unitInfo.Value); + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredUnits = Units; + return; + } + + FilteredUnits = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + foreach (var family in Units) + { + if (family.Label.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + family.Unit.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(family); + } + } + + return searchResults; + }); + } + catch + { + // ignored + } + } + + partial void OnUnitsChanged(List value) + { + FilteredUnits = value; + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockBoundingBoxVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockBoundingBoxVisualizationViewModel.cs new file mode 100644 index 000000000..d1b2fa86c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockBoundingBoxVisualizationViewModel.cs @@ -0,0 +1,43 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MockBoundingBoxVisualizationViewModel : ObservableObject, IBoundingBoxVisualizationViewModel +{ + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _surfaceColor; + [ObservableProperty] private Color _edgeColor; + [ObservableProperty] private Color _axisColor; + + [ObservableProperty] private bool _showSurface; + [ObservableProperty] private bool _showEdge; + [ObservableProperty] private bool _showAxis; + + public MockBoundingBoxVisualizationViewModel() + { + var faker = new Faker(); + + Transparency = faker.Random.Double(0, 100); + SurfaceColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + EdgeColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + AxisColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowSurface = faker.Random.Bool(); + ShowEdge = faker.Random.Bool(); + ShowAxis = faker.Random.Bool(); + } + + public void RegisterServer(object boundingBoxXyz) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockFaceVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockFaceVisualizationViewModel.cs new file mode 100644 index 000000000..a545d4fd9 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockFaceVisualizationViewModel.cs @@ -0,0 +1,48 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MockFaceVisualizationViewModel : ObservableObject, IFaceVisualizationViewModel +{ + [ObservableProperty] private double _extrusion; + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _surfaceColor; + [ObservableProperty] private Color _meshColor; + [ObservableProperty] private Color _normalVectorColor; + + [ObservableProperty] private bool _showSurface; + [ObservableProperty] private bool _showMeshGrid; + [ObservableProperty] private bool _showNormalVector; + + public double MinExtrusion { get; } + + public MockFaceVisualizationViewModel() + { + var faker = new Faker(); + + MinExtrusion = 0; + Transparency = faker.Random.Double(0, 100); + Extrusion = faker.Random.Double(0, 24); + SurfaceColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + MeshColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + NormalVectorColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowSurface = faker.Random.Bool(); + ShowMeshGrid = faker.Random.Bool(); + ShowNormalVector = faker.Random.Bool(); + } + + public void RegisterServer(object face) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockMeshVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockMeshVisualizationViewModel.cs new file mode 100644 index 000000000..76dfbd53c --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockMeshVisualizationViewModel.cs @@ -0,0 +1,48 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MockMeshVisualizationViewModel : ObservableObject, IMeshVisualizationViewModel +{ + [ObservableProperty] private double _extrusion; + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _surfaceColor; + [ObservableProperty] private Color _meshColor; + [ObservableProperty] private Color _normalVectorColor; + + [ObservableProperty] private bool _showSurface; + [ObservableProperty] private bool _showMeshGrid; + [ObservableProperty] private bool _showNormalVector; + + public MockMeshVisualizationViewModel() + { + var faker = new Faker(); + + MinExtrusion = 0; + Transparency = faker.Random.Double(0, 100); + Extrusion = faker.Random.Double(0, 24); + SurfaceColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + MeshColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + NormalVectorColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowSurface = faker.Random.Bool(); + ShowMeshGrid = faker.Random.Bool(); + ShowNormalVector = faker.Random.Bool(); + } + + public double MinExtrusion { get; } + + public void RegisterServer(object mesh) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockPolylineVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockPolylineVisualizationViewModel.cs new file mode 100644 index 000000000..69ff34355 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockPolylineVisualizationViewModel.cs @@ -0,0 +1,48 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MockPolylineVisualizationViewModel : ObservableObject, IPolylineVisualizationViewModel +{ + [ObservableProperty] private double _diameter; + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _surfaceColor; + [ObservableProperty] private Color _curveColor; + [ObservableProperty] private Color _directionColor; + + [ObservableProperty] private bool _showSurface; + [ObservableProperty] private bool _showCurve; + [ObservableProperty] private bool _showDirection; + + public MockPolylineVisualizationViewModel() + { + var faker = new Faker(); + + MinThickness = 0; + Transparency = faker.Random.Double(0, 100); + Diameter = faker.Random.Double(0, 6); + SurfaceColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + CurveColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + DirectionColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowSurface = faker.Random.Bool(); + ShowCurve = faker.Random.Bool(); + ShowDirection = faker.Random.Bool(); + } + + public double MinThickness { get; } + + public void RegisterServer(object curveOrEdge) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockSolidVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockSolidVisualizationViewModel.cs new file mode 100644 index 000000000..9c35556d0 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/MockSolidVisualizationViewModel.cs @@ -0,0 +1,41 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MockSolidVisualizationViewModel : ObservableObject, ISolidVisualizationViewModel +{ + [ObservableProperty] private double _scale; + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _faceColor; + [ObservableProperty] private Color _edgeColor; + + [ObservableProperty] private bool _showFace; + [ObservableProperty] private bool _showEdge; + + public MockSolidVisualizationViewModel() + { + var faker = new Faker(); + + Transparency = faker.Random.Double(0, 100); + Scale = faker.Random.Double(100, 400); + FaceColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + EdgeColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowFace = faker.Random.Bool(); + ShowEdge = faker.Random.Bool(); + } + + public void RegisterServer(object solid) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/XyzVisualizationViewModel.cs b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/XyzVisualizationViewModel.cs new file mode 100644 index 000000000..33fa0da15 --- /dev/null +++ b/source/RevitLookup.UI.Playground/Mockups/ViewModels/Visualization/XyzVisualizationViewModel.cs @@ -0,0 +1,50 @@ +using System.Windows.Media; +using Bogus; +using CommunityToolkit.Mvvm.ComponentModel; +using JetBrains.Annotations; +using RevitLookup.Abstractions.ViewModels.Visualization; + +namespace RevitLookup.UI.Playground.Mockups.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class XyzVisualizationViewModel : ObservableObject, IXyzVisualizationViewModel +{ + [ObservableProperty] private double _axisLength; + [ObservableProperty] private double _transparency; + + [ObservableProperty] private Color _xColor; + [ObservableProperty] private Color _yColor; + [ObservableProperty] private Color _zColor; + + [ObservableProperty] private bool _showPlane; + [ObservableProperty] private bool _showXAxis; + [ObservableProperty] private bool _showYAxis; + [ObservableProperty] private bool _showZAxis; + + public XyzVisualizationViewModel() + { + var faker = new Faker(); + + MinAxisLength = 0; + Transparency = faker.Random.Double(0, 100); + AxisLength = faker.Random.Double(0, 24); + XColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + YColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + ZColor = Color.FromRgb(faker.Random.Byte(), faker.Random.Byte(), faker.Random.Byte()); + + ShowPlane = faker.Random.Bool(); + ShowXAxis = faker.Random.Bool(); + ShowYAxis = faker.Random.Bool(); + ShowZAxis = faker.Random.Bool(); + } + + public double MinAxisLength { get; } + + public void RegisterServer(object xyz) + { + } + + public void UnregisterServer() + { + } +} \ No newline at end of file diff --git a/source/RevitLookup.UI.Playground/RevitLookup.UI.Playground.csproj b/source/RevitLookup.UI.Playground/RevitLookup.UI.Playground.csproj new file mode 100644 index 000000000..55c844872 --- /dev/null +++ b/source/RevitLookup.UI.Playground/RevitLookup.UI.Playground.csproj @@ -0,0 +1,38 @@ + + + + true + WinExe + net8.0-windows + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/RevitLookup.UI/Animations/TransitionAnimationProvider.cs b/source/RevitLookup.UI/Animations/TransitionAnimationProvider.cs index db6df4753..71edf8000 100644 --- a/source/RevitLookup.UI/Animations/TransitionAnimationProvider.cs +++ b/source/RevitLookup.UI/Animations/TransitionAnimationProvider.cs @@ -27,33 +27,19 @@ public static class TransitionAnimationProvider /// Selected transition type. /// Transition duration. /// Returns if the transition was applied. Otherwise . - public static bool ApplyTransition(object element, Transition type, int duration) + public static bool ApplyTransition(object? element, Transition type, int duration) { - if (type == Transition.None) + if ( + type == Transition.None + || !HardwareAcceleration.IsSupported(RenderingTier.PartialAcceleration) + || element is not UIElement uiElement + || duration < 10 + ) { return false; } - // Disable transitions for non-accelerated devices. - if (!HardwareAcceleration.IsSupported(RenderingTier.PartialAcceleration)) - { - return false; - } - - if (element is not UIElement uiElement) - { - return false; - } - - if (duration < 10) - { - return false; - } - - if (duration > 10000) - { - duration = 10000; - } + duration = duration > 10000 ? 10000 : duration; var timespanDuration = new Duration(TimeSpan.FromMilliseconds(duration)); @@ -122,9 +108,10 @@ private static void FadeInWithSlideTransition(UIElement animatedUiElement, Durat animatedUiElement.SetCurrentValue(UIElement.RenderTransformOriginProperty, new Point(0.5, 0.5)); } - animatedUiElement - .RenderTransform - .BeginAnimation(TranslateTransform.YProperty, translateDoubleAnimation); + animatedUiElement.RenderTransform.BeginAnimation( + TranslateTransform.YProperty, + translateDoubleAnimation + ); var opacityDoubleAnimation = new DoubleAnimation { @@ -160,9 +147,10 @@ private static void SlideBottomTransition(UIElement animatedUiElement, Duration animatedUiElement.SetCurrentValue(UIElement.RenderTransformOriginProperty, new Point(0.5, 0.5)); } - animatedUiElement - .RenderTransform - .BeginAnimation(TranslateTransform.YProperty, translateDoubleAnimation); + animatedUiElement.RenderTransform.BeginAnimation( + TranslateTransform.YProperty, + translateDoubleAnimation + ); } private static void SlideRightTransition(UIElement animatedUiElement, Duration duration) @@ -188,9 +176,10 @@ private static void SlideRightTransition(UIElement animatedUiElement, Duration d animatedUiElement.SetCurrentValue(UIElement.RenderTransformOriginProperty, new Point(0.5, 0.5)); } - animatedUiElement - .RenderTransform - .BeginAnimation(TranslateTransform.XProperty, translateDoubleAnimation); + animatedUiElement.RenderTransform.BeginAnimation( + TranslateTransform.XProperty, + translateDoubleAnimation + ); } private static void SlideLeftTransition(UIElement animatedUiElement, Duration duration) @@ -216,8 +205,9 @@ private static void SlideLeftTransition(UIElement animatedUiElement, Duration du animatedUiElement.SetCurrentValue(UIElement.RenderTransformOriginProperty, new Point(0.5, 0.5)); } - animatedUiElement - .RenderTransform - .BeginAnimation(TranslateTransform.XProperty, translateDoubleAnimation); + animatedUiElement.RenderTransform.BeginAnimation( + TranslateTransform.XProperty, + translateDoubleAnimation + ); } } diff --git a/source/RevitLookup.UI/Appearance/ApplicationAccentColorManager.cs b/source/RevitLookup.UI/Appearance/ApplicationAccentColorManager.cs index 065dd8505..120881098 100644 --- a/source/RevitLookup.UI/Appearance/ApplicationAccentColorManager.cs +++ b/source/RevitLookup.UI/Appearance/ApplicationAccentColorManager.cs @@ -3,7 +3,7 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using Wpf.Ui.Extensions; +using System.Diagnostics; using Wpf.Ui.Interop; namespace Wpf.Ui.Appearance; @@ -41,7 +41,7 @@ public static Color SystemAccent { get { - var resource = Application.MainWindow.Resources["SystemAccentColor"]; + object? resource = UiApplication.Current.Resources["SystemAccentColor"]; if (resource is Color color) { @@ -64,7 +64,7 @@ public static Color PrimaryAccent { get { - var resource = Application.MainWindow.Resources["SystemAccentColorPrimary"]; + object? resource = UiApplication.Current.Resources["SystemAccentColorPrimary"]; if (resource is Color color) { @@ -87,7 +87,7 @@ public static Color SecondaryAccent { get { - var resource = Application.MainWindow.Resources["SystemAccentColorSecondary"]; + object? resource = UiApplication.Current.Resources["SystemAccentColorSecondary"]; if (resource is Color color) { @@ -110,7 +110,7 @@ public static Color TertiaryAccent { get { - var resource = Application.MainWindow.Resources["SystemAccentColorTertiary"]; + object? resource = UiApplication.Current.Resources["SystemAccentColorTertiary"]; if (resource is Color color) { @@ -132,9 +132,11 @@ public static Color TertiaryAccent /// Primary accent color. /// If , the colors will be different. /// If the color is taken from the Glass Color System, its brightness will be increased with the help of the operations on HSV space. - public static void Apply(Color systemAccent, + public static void Apply( + Color systemAccent, ApplicationTheme applicationTheme = ApplicationTheme.Light, - bool systemGlassColor = false) + bool systemGlassColor = false + ) { if (systemGlassColor) { @@ -199,57 +201,55 @@ public static Color GetColorizationColor() /// /// Updates application resources. /// - private static void UpdateColorResources(Color systemAccent, + private static void UpdateColorResources( + Color systemAccent, Color primaryAccent, Color secondaryAccent, - Color tertiaryAccent) + Color tertiaryAccent + ) { -#if DEBUG - System.Diagnostics.Debug.WriteLine("INFO | SystemAccentColor: " + systemAccent, "Wpf.Ui.Accent"); - System - .Diagnostics - .Debug - .WriteLine("INFO | SystemAccentColorPrimary: " + primaryAccent, "Wpf.Ui.Accent"); - System - .Diagnostics - .Debug - .WriteLine("INFO | SystemAccentColorSecondary: " + secondaryAccent, "Wpf.Ui.Accent"); - System - .Diagnostics - .Debug - .WriteLine("INFO | SystemAccentColorTertiary: " + tertiaryAccent, "Wpf.Ui.Accent"); -#endif + Debug.WriteLine("INFO | SystemAccentColor: " + systemAccent, "Wpf.Ui.Accent"); + Debug.WriteLine( + "INFO | SystemAccentColorPrimary: " + primaryAccent, + "Wpf.Ui.Accent" + ); + Debug.WriteLine( + "INFO | SystemAccentColorSecondary: " + secondaryAccent, + "Wpf.Ui.Accent" + ); + Debug.WriteLine( + "INFO | SystemAccentColorTertiary: " + tertiaryAccent, + "Wpf.Ui.Accent" + ); if (secondaryAccent.GetBrightness() > BackgroundBrightnessThresholdValue) { -#if DEBUG - System.Diagnostics.Debug.WriteLine("INFO | Text on accent is DARK", "Wpf.Ui.Accent"); -#endif - Application.MainWindow.Resources["TextOnAccentFillColorPrimary"] = Color.FromArgb( + Debug.WriteLine("INFO | Text on accent is DARK", "Wpf.Ui.Accent"); + UiApplication.Current.Resources["TextOnAccentFillColorPrimary"] = Color.FromArgb( 0xFF, 0x00, 0x00, 0x00 ); - Application.MainWindow.Resources["TextOnAccentFillColorSecondary"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorSecondary"] = Color.FromArgb( 0x80, 0x00, 0x00, 0x00 ); - Application.MainWindow.Resources["TextOnAccentFillColorDisabled"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorDisabled"] = Color.FromArgb( 0x77, 0x00, 0x00, 0x00 ); - Application.MainWindow.Resources["TextOnAccentFillColorSelectedText"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorSelectedText"] = Color.FromArgb( 0x00, 0x00, 0x00, 0x00 ); - Application.MainWindow.Resources["AccentTextFillColorDisabled"] = Color.FromArgb( + UiApplication.Current.Resources["AccentTextFillColorDisabled"] = Color.FromArgb( 0x5D, 0x00, 0x00, @@ -258,34 +258,32 @@ private static void UpdateColorResources(Color systemAccent, } else { -#if DEBUG - System.Diagnostics.Debug.WriteLine("INFO | Text on accent is LIGHT", "Wpf.Ui.Accent"); -#endif - Application.MainWindow.Resources["TextOnAccentFillColorPrimary"] = Color.FromArgb( + Debug.WriteLine("INFO | Text on accent is LIGHT", "Wpf.Ui.Accent"); + UiApplication.Current.Resources["TextOnAccentFillColorPrimary"] = Color.FromArgb( 0xFF, 0xFF, 0xFF, 0xFF ); - Application.MainWindow.Resources["TextOnAccentFillColorSecondary"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorSecondary"] = Color.FromArgb( 0x80, 0xFF, 0xFF, 0xFF ); - Application.MainWindow.Resources["TextOnAccentFillColorDisabled"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorDisabled"] = Color.FromArgb( 0x87, 0xFF, 0xFF, 0xFF ); - Application.MainWindow.Resources["TextOnAccentFillColorSelectedText"] = Color.FromArgb( + UiApplication.Current.Resources["TextOnAccentFillColorSelectedText"] = Color.FromArgb( 0xFF, 0xFF, 0xFF, 0xFF ); - Application.MainWindow.Resources["AccentTextFillColorDisabled"] = Color.FromArgb( + UiApplication.Current.Resources["AccentTextFillColorDisabled"] = Color.FromArgb( 0x5D, 0xFF, 0xFF, @@ -293,20 +291,21 @@ private static void UpdateColorResources(Color systemAccent, ); } - Application.MainWindow.Resources["SystemAccentColor"] = systemAccent; - Application.MainWindow.Resources["SystemAccentColorPrimary"] = primaryAccent; - Application.MainWindow.Resources["SystemAccentColorSecondary"] = secondaryAccent; - Application.MainWindow.Resources["SystemAccentColorTertiary"] = tertiaryAccent; + UiApplication.Current.Resources["SystemAccentColor"] = systemAccent; + UiApplication.Current.Resources["SystemAccentColorPrimary"] = primaryAccent; + UiApplication.Current.Resources["SystemAccentColorSecondary"] = secondaryAccent; + UiApplication.Current.Resources["SystemAccentColorTertiary"] = tertiaryAccent; - Application.MainWindow.Resources["SystemAccentBrush"] = secondaryAccent.ToBrush(); - Application.MainWindow.Resources["SystemFillColorAttentionBrush"] = secondaryAccent.ToBrush(); - Application.MainWindow.Resources["AccentTextFillColorPrimaryBrush"] = tertiaryAccent.ToBrush(); - Application.MainWindow.Resources["AccentTextFillColorSecondaryBrush"] = tertiaryAccent.ToBrush(); - Application.MainWindow.Resources["AccentTextFillColorTertiaryBrush"] = secondaryAccent.ToBrush(); - Application.MainWindow.Resources["AccentFillColorSelectedTextBackgroundBrush"] = systemAccent.ToBrush(); - Application.MainWindow.Resources["AccentFillColorDefaultBrush"] = secondaryAccent.ToBrush(); + UiApplication.Current.Resources["SystemAccentBrush"] = secondaryAccent.ToBrush(); + UiApplication.Current.Resources["SystemFillColorAttentionBrush"] = secondaryAccent.ToBrush(); + UiApplication.Current.Resources["AccentTextFillColorPrimaryBrush"] = tertiaryAccent.ToBrush(); + UiApplication.Current.Resources["AccentTextFillColorSecondaryBrush"] = tertiaryAccent.ToBrush(); + UiApplication.Current.Resources["AccentTextFillColorTertiaryBrush"] = secondaryAccent.ToBrush(); + UiApplication.Current.Resources["AccentFillColorSelectedTextBackgroundBrush"] = + systemAccent.ToBrush(); + UiApplication.Current.Resources["AccentFillColorDefaultBrush"] = secondaryAccent.ToBrush(); - Application.MainWindow.Resources["AccentFillColorSecondaryBrush"] = secondaryAccent.ToBrush(0.9); - Application.MainWindow.Resources["AccentFillColorTertiaryBrush"] = secondaryAccent.ToBrush(0.8); + UiApplication.Current.Resources["AccentFillColorSecondaryBrush"] = secondaryAccent.ToBrush(0.9); + UiApplication.Current.Resources["AccentFillColorTertiaryBrush"] = secondaryAccent.ToBrush(0.8); } } \ No newline at end of file diff --git a/source/RevitLookup.UI/Appearance/ApplicationTheme.cs b/source/RevitLookup.UI/Appearance/ApplicationTheme.cs index c2b9f5420..a7d616208 100644 --- a/source/RevitLookup.UI/Appearance/ApplicationTheme.cs +++ b/source/RevitLookup.UI/Appearance/ApplicationTheme.cs @@ -34,4 +34,4 @@ public enum ApplicationTheme /// High contract application theme. /// HighContrast -} \ No newline at end of file +} diff --git a/source/RevitLookup.UI/Appearance/ApplicationThemeManager.cs b/source/RevitLookup.UI/Appearance/ApplicationThemeManager.cs index 15a0b88e9..f1fc741ce 100644 --- a/source/RevitLookup.UI/Appearance/ApplicationThemeManager.cs +++ b/source/RevitLookup.UI/Appearance/ApplicationThemeManager.cs @@ -3,7 +3,8 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using System.Runtime.CompilerServices; +using System.Collections; +using System.Diagnostics; using Wpf.Ui.Controls; namespace Wpf.Ui.Appearance; @@ -36,7 +37,7 @@ public static class ApplicationThemeManager { private static ApplicationTheme _cachedApplicationTheme = ApplicationTheme.Unknown; - internal const string LibraryNamespace = "ui;"; + internal const string LibraryNamespace = "revitlookup.ui;"; public const string ThemesDictionaryPath = "pack://application:,,,/RevitLookup.UI;component/Resources/Theme/"; @@ -63,15 +64,16 @@ public static class ApplicationThemeManager /// Theme to set. /// Whether the custom background effect should be applied. /// Whether the color accents should be changed. - /// If , bypasses the app's theme compatibility check and tries to force the change of a background effect. - public static void Apply(ApplicationTheme applicationTheme, + public static void Apply( + ApplicationTheme applicationTheme, WindowBackdropType backgroundEffect = WindowBackdropType.Mica, - bool updateAccent = true, - bool forceBackground = false) + bool updateAccent = true + ) { if (updateAccent) { - ApplicationAccentColorManager.Apply(ApplicationAccentColorManager.GetColorizationColor(), + ApplicationAccentColorManager.Apply( + ApplicationAccentColorManager.GetColorizationColor(), applicationTheme, false ); @@ -82,9 +84,9 @@ public static void Apply(ApplicationTheme applicationTheme, return; } - var appDictionaries = new ResourceDictionaryManager(LibraryNamespace); + ResourceDictionaryManager appDictionaries = new(LibraryNamespace); - var themeDictionaryName = "Light"; + string themeDictionaryName = "Light"; switch (applicationTheme) { @@ -92,59 +94,27 @@ public static void Apply(ApplicationTheme applicationTheme, themeDictionaryName = "Dark"; break; case ApplicationTheme.HighContrast: - switch (ApplicationThemeManager.GetSystemTheme()) + themeDictionaryName = GetSystemTheme() switch { - case SystemTheme.HC1: - themeDictionaryName = "HC1"; - break; - case SystemTheme.HC2: - themeDictionaryName = "HC2"; - break; - case SystemTheme.HCBlack: - themeDictionaryName = "HCBlack"; - break; - case SystemTheme.HCWhite: - default: - themeDictionaryName = "HCWhite"; - break; - } - + SystemTheme.HC1 => "HC1", + SystemTheme.HC2 => "HC2", + SystemTheme.HCBlack => "HCBlack", + SystemTheme.HCWhite => "HCWhite", + _ => "HCWhite", + }; break; } - var isUpdated = appDictionaries.UpdateDictionary("theme", + bool isUpdated = appDictionaries.UpdateDictionary( + "theme", new Uri(ThemesDictionaryPath + themeDictionaryName + ".xaml", UriKind.Absolute) ); - //var wpfUiDictionary = appDictionaries.GetDictionary("wpf.ui"); - - // Force reloading ALL dictionaries - // Works but is terrible - //var isCoreUpdated = appDictionaries.UpdateDictionary( - // "wpf.ui", - // new Uri( - // AppearanceData.LibraryDictionariesUri + "Wpf.Ui.xaml", - // UriKind.Absolute - // ) - //); - - //var isBrushesUpdated = appDictionaries.UpdateDictionary( - // "assets/brushes", - // new Uri( - // AppearanceData.LibraryDictionariesUri + "Assets/Brushes.xaml", - // UriKind.Absolute - // ) - // ); - -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine( - $"INFO | {typeof(ApplicationThemeManager)} tries to update theme to {themeDictionaryName} ({applicationTheme}): {isUpdated}", - nameof(ApplicationThemeManager) - ); -#endif + Debug.WriteLine( + $"INFO | {typeof(ApplicationThemeManager)} tries to update theme to {themeDictionaryName} ({applicationTheme}): {isUpdated}", + nameof(ApplicationThemeManager) + ); + if (!isUpdated) { return; @@ -156,14 +126,28 @@ public static void Apply(ApplicationTheme applicationTheme, Changed?.Invoke(applicationTheme, ApplicationAccentColorManager.SystemAccent); - if (Application.MainWindow is not null) + if (UiApplication.Current.MainWindow is { } mainWindow) { - WindowBackgroundManager.UpdateBackground( - Application.MainWindow, - applicationTheme, - backgroundEffect, - forceBackground - ); + WindowBackgroundManager.UpdateBackground(mainWindow, applicationTheme, backgroundEffect); + } + } + + /// + /// Applies Resources in the . + /// + public static void Apply(FrameworkElement frameworkElement) + { + if (frameworkElement.Resources.MergedDictionaries.Count < UiApplication.Current.Resources.MergedDictionaries.Count) + { + foreach (var dictionary in UiApplication.Current.Resources.MergedDictionaries) + { + frameworkElement.Resources.MergedDictionaries.Add(dictionary); + } + } + + foreach (DictionaryEntry resource in UiApplication.Current.Resources) + { + frameworkElement.Resources[resource.Key] = resource.Value; } } @@ -191,7 +175,7 @@ systemTheme is SystemTheme.HC1 or SystemTheme.HC2 or SystemTheme.HCBlack or Syst themeToSet = ApplicationTheme.HighContrast; } - Apply(themeToSet); + Apply(themeToSet, updateAccent: updateAccent); } /// @@ -281,21 +265,21 @@ private static void FetchApplicationTheme() return; } - var themeUri = themeDictionary.Source.ToString().Trim().ToLower(); + string themeUri = themeDictionary.Source.ToString(); - if (themeUri.Contains("light")) + if (themeUri.Contains("light", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.Light; } - if (themeUri.Contains("dark")) + if (themeUri.Contains("dark", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.Dark; } - if (themeUri.Contains("highcontrast")) + if (themeUri.Contains("highcontrast", StringComparison.OrdinalIgnoreCase)) { _cachedApplicationTheme = ApplicationTheme.HighContrast; } } -} +} \ No newline at end of file diff --git a/source/RevitLookup.UI/Appearance/ObservedWindow.cs b/source/RevitLookup.UI/Appearance/ObservedWindow.cs index 2febc935f..44e4c586c 100644 --- a/source/RevitLookup.UI/Appearance/ObservedWindow.cs +++ b/source/RevitLookup.UI/Appearance/ObservedWindow.cs @@ -7,40 +7,60 @@ namespace Wpf.Ui.Appearance; +/// +/// Represents a window that is being observed for changes in appearance. +/// internal class ObservedWindow { private readonly HwndSource _source; - public ObservedWindow( - IntPtr handle, - WindowBackdropType backdrop, - bool forceBackgroundReplace, - bool updateAccents - ) + /// + /// Initializes a new instance of the ObservedWindow class. + /// + /// The handle of the window. + /// The backdrop type of the window. + /// Indicates whether to update accents. + public ObservedWindow(IntPtr handle, WindowBackdropType backdrop, bool updateAccents) { Handle = handle; Backdrop = backdrop; - ForceBackgroundReplace = forceBackgroundReplace; UpdateAccents = updateAccents; HasHook = false; - var windowSource = HwndSource.FromHwnd(handle); + HwndSource? windowSource = HwndSource.FromHwnd(handle); _source = windowSource ?? throw new InvalidOperationException("Unable to determine the window source."); } + /// + /// Gets the root visual of the window. + /// public Window? RootVisual => (Window?)_source.RootVisual; + /// + /// Gets the handle of the window. + /// public IntPtr Handle { get; } + /// + /// Gets the backdrop type of the window. + /// public WindowBackdropType Backdrop { get; } - public bool ForceBackgroundReplace { get; } - + /// + /// Gets a value indicating whether to update accents. + /// public bool UpdateAccents { get; } + /// + /// Gets a value indicating whether the window has a hook. + /// public bool HasHook { get; private set; } + /// + /// Adds a hook to the window. + /// + /// The hook to add. public void AddHook(HwndSourceHook hook) { _source.AddHook(hook); @@ -48,6 +68,10 @@ public void AddHook(HwndSourceHook hook) HasHook = true; } + /// + /// Removes a hook from the window. + /// + /// The hook to remove. public void RemoveHook(HwndSourceHook hook) { _source.RemoveHook(hook); diff --git a/source/RevitLookup.UI/Appearance/ResourceDictionaryManager.cs b/source/RevitLookup.UI/Appearance/ResourceDictionaryManager.cs index 5bc7594d3..709fdc581 100644 --- a/source/RevitLookup.UI/Appearance/ResourceDictionaryManager.cs +++ b/source/RevitLookup.UI/Appearance/ResourceDictionaryManager.cs @@ -13,7 +13,7 @@ namespace Wpf.Ui.Appearance; internal class ResourceDictionaryManager { /// - /// Namespace, e.g. the library the resource is being searched for. + /// Gets the namespace, e.g. the library the resource is being searched for. /// public string SearchNamespace { get; } @@ -46,19 +46,17 @@ public bool HasDictionary(string resourceLookup) return null; } - resourceLookup = resourceLookup.ToLower().Trim(); - foreach (ResourceDictionary t in applicationDictionaries) { string resourceDictionaryUri; if (t?.Source != null) { - resourceDictionaryUri = t.Source.ToString().ToLower().Trim(); + resourceDictionaryUri = t.Source.ToString(); if ( - resourceDictionaryUri.Contains(SearchNamespace) - && resourceDictionaryUri.Contains(resourceLookup) + resourceDictionaryUri.Contains(SearchNamespace, StringComparison.OrdinalIgnoreCase) + && resourceDictionaryUri.Contains(resourceLookup, StringComparison.OrdinalIgnoreCase) ) { return t; @@ -72,11 +70,11 @@ public bool HasDictionary(string resourceLookup) continue; } - resourceDictionaryUri = t1.Source.ToString().ToLower().Trim(); + resourceDictionaryUri = t1.Source.ToString(); if ( - !resourceDictionaryUri.Contains(SearchNamespace) - || !resourceDictionaryUri.Contains(resourceLookup) + !resourceDictionaryUri.Contains(SearchNamespace, StringComparison.OrdinalIgnoreCase) + || !resourceDictionaryUri.Contains(resourceLookup, StringComparison.OrdinalIgnoreCase) ) { continue; @@ -97,8 +95,8 @@ public bool HasDictionary(string resourceLookup) /// if the dictionary was updated. otherwise. public bool UpdateDictionary(string resourceLookup, Uri? newResourceUri) { - Collection applicationDictionaries = Application - .MainWindow + Collection applicationDictionaries = UiApplication + .Current .Resources .MergedDictionaries; @@ -107,19 +105,17 @@ public bool UpdateDictionary(string resourceLookup, Uri? newResourceUri) return false; } - resourceLookup = resourceLookup.ToLower().Trim(); - for (var i = 0; i < applicationDictionaries.Count; i++) { string sourceUri; if (applicationDictionaries[i]?.Source != null) { - sourceUri = applicationDictionaries[i].Source.ToString().ToLower().Trim(); + sourceUri = applicationDictionaries[i].Source.ToString(); - if (sourceUri.Contains(SearchNamespace) && sourceUri.Contains(resourceLookup)) + if (sourceUri.Contains(SearchNamespace, StringComparison.OrdinalIgnoreCase) && sourceUri.Contains(resourceLookup, StringComparison.OrdinalIgnoreCase)) { - applicationDictionaries[i] = new() { Source = newResourceUri }; + applicationDictionaries[i] = new() {Source = newResourceUri}; return true; } @@ -135,16 +131,14 @@ public bool UpdateDictionary(string resourceLookup, Uri? newResourceUri) sourceUri = applicationDictionaries[i] .MergedDictionaries[j] .Source - .ToString() - .ToLower() - .Trim(); + .ToString(); - if (!sourceUri.Contains(SearchNamespace) || !sourceUri.Contains(resourceLookup)) + if (!sourceUri.Contains(SearchNamespace, StringComparison.OrdinalIgnoreCase) || !sourceUri.Contains(resourceLookup, StringComparison.OrdinalIgnoreCase)) { continue; } - applicationDictionaries[i].MergedDictionaries[j] = new() { Source = newResourceUri }; + applicationDictionaries[i].MergedDictionaries[j] = new() {Source = newResourceUri}; return true; } @@ -155,6 +149,6 @@ public bool UpdateDictionary(string resourceLookup, Uri? newResourceUri) private Collection GetApplicationMergedDictionaries() { - return Application.MainWindow.Resources.MergedDictionaries; + return UiApplication.Current.Resources.MergedDictionaries; } -} +} \ No newline at end of file diff --git a/source/RevitLookup.UI/Appearance/SystemTheme.cs b/source/RevitLookup.UI/Appearance/SystemTheme.cs index e04ecc7ee..23cee95c1 100644 --- a/source/RevitLookup.UI/Appearance/SystemTheme.cs +++ b/source/RevitLookup.UI/Appearance/SystemTheme.cs @@ -51,22 +51,22 @@ public enum SystemTheme HC2, /// - /// First custom, kinda purple Windows 11 theme. + /// Dark theme: Glow /// Glow, /// - /// Second custom, kinda red Windows 11 theme. + /// Dark theme: Captured Motion /// CapturedMotion, /// - /// Third custom, kinda washed off cyan Windows 11 theme. + /// Light theme: Sunrise /// Sunrise, /// - /// Fourth custom, kinda gray Windows 11 theme. + /// Light theme: Flow /// Flow } diff --git a/source/RevitLookup.UI/Appearance/SystemThemeManager.cs b/source/RevitLookup.UI/Appearance/SystemThemeManager.cs index 4b48e1899..a46d6fa6c 100644 --- a/source/RevitLookup.UI/Appearance/SystemThemeManager.cs +++ b/source/RevitLookup.UI/Appearance/SystemThemeManager.cs @@ -65,71 +65,69 @@ private static SystemTheme GetCurrentSystemTheme() "CurrentTheme", "aero.theme" ) as string - ?? String.Empty; + ?? string.Empty; - if (!String.IsNullOrEmpty(currentTheme)) + if (!string.IsNullOrEmpty(currentTheme)) { - currentTheme = currentTheme.ToLower().Trim(); - // This may be changed in the next versions, check the Insider previews - if (currentTheme.Contains("basic.theme")) + if (currentTheme.Contains("basic.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Light; } - if (currentTheme.Contains("aero.theme")) + if (currentTheme.Contains("aero.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Light; } - if (currentTheme.Contains("dark.theme")) + if (currentTheme.Contains("dark.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Dark; } - if (currentTheme.Contains("hcblack.theme")) + if (currentTheme.Contains("hcblack.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.HCBlack; } - if (currentTheme.Contains("hcwhite.theme")) + if (currentTheme.Contains("hcwhite.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.HCWhite; } - if (currentTheme.Contains("hc1.theme")) + if (currentTheme.Contains("hc1.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.HC1; } - if (currentTheme.Contains("hc2.theme")) + if (currentTheme.Contains("hc2.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.HC2; } - if (currentTheme.Contains("themea.theme")) + if (currentTheme.Contains("themea.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Glow; } - if (currentTheme.Contains("themeb.theme")) + if (currentTheme.Contains("themeb.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.CapturedMotion; } - if (currentTheme.Contains("themec.theme")) + if (currentTheme.Contains("themec.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Sunrise; } - if (currentTheme.Contains("themed.theme")) + if (currentTheme.Contains("themed.theme", StringComparison.OrdinalIgnoreCase)) { return SystemTheme.Flow; } } - //if (currentTheme.Contains("custom.theme")) - // return ; custom can be light or dark + /*if (currentTheme.Contains("custom.theme")) + return ; custom can be light or dark*/ var rawAppsUseLightTheme = Registry.GetValue( "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme", @@ -154,4 +152,4 @@ private static SystemTheme GetCurrentSystemTheme() return rawSystemUsesLightTheme is 0 ? SystemTheme.Dark : SystemTheme.Light; } -} +} \ No newline at end of file diff --git a/source/RevitLookup.UI/Appearance/SystemThemeWatcher.cs b/source/RevitLookup.UI/Appearance/SystemThemeWatcher.cs index fbf88ec5b..7d300fe68 100644 --- a/source/RevitLookup.UI/Appearance/SystemThemeWatcher.cs +++ b/source/RevitLookup.UI/Appearance/SystemThemeWatcher.cs @@ -25,7 +25,7 @@ namespace Wpf.Ui.Appearance; /// public static class SystemThemeWatcher { - private static readonly ICollection _observedWindows = new List(); + private static readonly List _observedWindows = []; /// /// Watches the and applies the background effect and theme according to the system theme. @@ -33,12 +33,10 @@ public static class SystemThemeWatcher /// The window that will be updated. /// Background effect to be applied when changing the theme. /// If , the accents will be updated when the change is detected. - /// If , bypasses the app's theme compatibility check and tries to force the change of a background effect. public static void Watch( Window? window, WindowBackdropType backdrop = WindowBackdropType.Mica, - bool updateAccents = true, - bool forceBackgroundReplace = false + bool updateAccents = true ) { if (window is null) @@ -48,34 +46,24 @@ public static void Watch( if (window.IsLoaded) { - ObserveLoadedWindow(window, backdrop, updateAccents, forceBackgroundReplace); + ObserveLoadedWindow(window, backdrop, updateAccents); } else { - ObserveWindowWhenLoaded(window, backdrop, updateAccents, forceBackgroundReplace); + ObserveWindowWhenLoaded(window, backdrop, updateAccents); } - if (!_observedWindows.Any()) + if (_observedWindows.Count == 0) { -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine( - $"INFO | {typeof(SystemThemeWatcher)} changed the app theme on initialization.", - nameof(SystemThemeWatcher) - ); -#endif + System.Diagnostics.Debug.WriteLine( + $"INFO | {typeof(SystemThemeWatcher)} changed the app theme on initialization.", + nameof(SystemThemeWatcher) + ); ApplicationThemeManager.ApplySystemTheme(updateAccents); } } - private static void ObserveLoadedWindow( - Window window, - WindowBackdropType backdrop, - bool updateAccents, - bool forceBackgroundReplace - ) + private static void ObserveLoadedWindow(Window window, WindowBackdropType backdrop, bool updateAccents) { IntPtr hWnd = (hWnd = new WindowInteropHelper(window).Handle) == IntPtr.Zero @@ -87,14 +75,13 @@ bool forceBackgroundReplace throw new InvalidOperationException("Window handle cannot be empty"); } - ObserveLoadedHandle(new ObservedWindow(hWnd, backdrop, forceBackgroundReplace, updateAccents)); + ObserveLoadedHandle(new ObservedWindow(hWnd, backdrop, updateAccents)); } private static void ObserveWindowWhenLoaded( Window window, WindowBackdropType backdrop, - bool updateAccents, - bool forceBackgroundReplace + bool updateAccents ) { window.Loaded += (_, _) => @@ -109,7 +96,7 @@ bool forceBackgroundReplace throw new InvalidOperationException("Window handle cannot be empty"); } - ObserveLoadedHandle(new ObservedWindow(hWnd, backdrop, forceBackgroundReplace, updateAccents)); + ObserveLoadedHandle(new ObservedWindow(hWnd, backdrop, updateAccents)); }; } @@ -117,15 +104,10 @@ private static void ObserveLoadedHandle(ObservedWindow observedWindow) { if (!observedWindow.HasHook) { -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine( - $"INFO | {observedWindow.Handle} ({observedWindow.RootVisual?.Title}) registered as watched window.", - nameof(SystemThemeWatcher) - ); -#endif + System.Diagnostics.Debug.WriteLine( + $"INFO | {observedWindow.Handle} ({observedWindow.RootVisual?.Title}) registered as watched window.", + nameof(SystemThemeWatcher) + ); observedWindow.AddHook(WndProc); _observedWindows.Add(observedWindow); } @@ -193,23 +175,17 @@ private static void UpdateObservedWindow(nint hWnd) ApplicationThemeManager.ApplySystemTheme(observedWindow.UpdateAccents); ApplicationTheme currentApplicationTheme = ApplicationThemeManager.GetAppTheme(); -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine( - $"INFO | {observedWindow.Handle} ({observedWindow.RootVisual?.Title}) triggered the application theme change to {ApplicationThemeManager.GetSystemTheme()}.", - nameof(SystemThemeWatcher) - ); -#endif + System.Diagnostics.Debug.WriteLine( + $"INFO | {observedWindow.Handle} ({observedWindow.RootVisual?.Title}) triggered the application theme change to {ApplicationThemeManager.GetSystemTheme()}.", + nameof(SystemThemeWatcher) + ); if (observedWindow.RootVisual is not null) { WindowBackgroundManager.UpdateBackground( observedWindow.RootVisual, currentApplicationTheme, - observedWindow.Backdrop, - observedWindow.ForceBackgroundReplace + observedWindow.Backdrop ); } } diff --git a/source/RevitLookup.UI/Appearance/WindowBackgroundManager.cs b/source/RevitLookup.UI/Appearance/WindowBackgroundManager.cs index d285939e5..769e888bc 100644 --- a/source/RevitLookup.UI/Appearance/WindowBackgroundManager.cs +++ b/source/RevitLookup.UI/Appearance/WindowBackgroundManager.cs @@ -5,13 +5,21 @@ using Wpf.Ui.Controls; using Wpf.Ui.Interop; -using Wpf.Ui.Win32; namespace Wpf.Ui.Appearance; /// /// Facilitates the management of the window background. /// +/// +/// +/// WindowBackgroundManager.UpdateBackground( +/// observedWindow.RootVisual, +/// currentApplicationTheme, +/// observedWindow.Backdrop +/// ); +/// +/// public static class WindowBackgroundManager { /// @@ -50,14 +58,24 @@ public static void RemoveDarkThemeFromWindow(Window? window) window.Loaded += (sender, _) => UnsafeNativeMethods.RemoveWindowDarkMode(sender as Window); } + [Obsolete("Use UpdateBackground(Window, ApplicationTheme, WindowBackdropType) instead.")] + public static void UpdateBackground( + Window? window, + ApplicationTheme applicationTheme, + WindowBackdropType backdrop, + bool forceBackground + ) + { + UpdateBackground(window, applicationTheme, backdrop); + } + /// /// Forces change to application background. Required if custom background effect was previously applied. /// public static void UpdateBackground( Window? window, ApplicationTheme applicationTheme, - WindowBackdropType backdrop, - bool forceBackground + WindowBackdropType backdrop ) { if (window is null) @@ -73,14 +91,16 @@ bool forceBackground } // This was required to update the background when moving from a HC theme to light/dark theme. However, this breaks theme proper light/dark theme changing on Windows 10. - else + // But window backdrop effects are not applied when it has an opaque (or any) background on W11 (so removing this breaks backdrop effects when switching themes), however, for legacy MICA it may not be required + // using existing variable, though the OS build which (officially) supports setting DWM_SYSTEMBACKDROP_TYPE attribute is build 22621 + // source: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type + if (Win32.Utilities.IsOSWindows11Insider1OrNewer && backdrop is not WindowBackdropType.None) { - if (Utilities.IsOSWindows11OrNewer) - { - _ = WindowBackdrop.RemoveBackground(window); - } + _ = WindowBackdrop.RemoveBackground(window); } + _ = WindowBackdrop.ApplyBackdrop(window, backdrop); + if (applicationTheme is ApplicationTheme.Dark) { ApplyDarkThemeToWindow(window); @@ -90,7 +110,9 @@ bool forceBackground RemoveDarkThemeFromWindow(window); } - foreach (var subWindow in window.OwnedWindows) + _ = WindowBackdrop.RemoveTitlebarBackground(window); + + foreach (object? subWindow in window.OwnedWindows) { if (subWindow is Window windowSubWindow) { @@ -104,52 +126,9 @@ bool forceBackground { RemoveDarkThemeFromWindow(windowSubWindow); } + + _ = WindowBackdrop.RemoveTitlebarBackground(window); } } - - // Do we really neeed this? - //if (!Win32.Utilities.IsOSWindows11OrNewer) - //{ - // var mainWindow = Application.Current.MainWindow; - - // if (mainWindow == null) - // return; - - // var backgroundColor = Application.Current.Resources["ApplicationBackgroundColor"]; - // if (backgroundColor is Color color) - // mainWindow.Background = new SolidColorBrush(color); - //} - - - // var mainWindow = Application.Current.MainWindow; - - // if (mainWindow == null) - // return; - - // // TODO: Do not refresh window presenter background if already applied - // var backgroundColor = Application.Current.Resources["ApplicationBackgroundColor"]; - // if (backgroundColor is Color color) - // mainWindow.Background = new SolidColorBrush(color); - - //#if DEBUG - // System.Diagnostics.Debug.WriteLine($"INFO | Current background color: {backgroundColor}", "Wpf.Ui.Theme"); - //#endif - - // var windowHandle = new WindowInteropHelper(mainWindow).Handle; - - // if (windowHandle == IntPtr.Zero) - // return; - - // Background.Remove(windowHandle); - - // //if (!IsAppMatchesSystem() || backgroundEffect == BackgroundType.Unknown) - // // return; - - // if (backgroundEffect == BackgroundType.Unknown) - // return; - - // // TODO: Improve - // if (Background.Apply(windowHandle, backgroundEffect, forceBackground)) - // mainWindow.Background = Brushes.Transparent; } } diff --git a/source/RevitLookup.UI/AutomationPeers/CardControlAutomationPeer.cs b/source/RevitLookup.UI/AutomationPeers/CardControlAutomationPeer.cs index a2da2b312..185b09c78 100644 --- a/source/RevitLookup.UI/AutomationPeers/CardControlAutomationPeer.cs +++ b/source/RevitLookup.UI/AutomationPeers/CardControlAutomationPeer.cs @@ -1,25 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + using System.Windows.Automation; using System.Windows.Automation.Peers; using Wpf.Ui.Controls; namespace Wpf.Ui.AutomationPeers; -internal class CardControlAutomationPeer : FrameworkElementAutomationPeer +/// +/// Provides UI Automation peer for the CardControl. +/// +internal class CardControlAutomationPeer(CardControl owner) : FrameworkElementAutomationPeer(owner) { - private readonly CardControl _owner; - - public CardControlAutomationPeer(CardControl owner) - : base(owner) - { - this._owner = owner; - } - protected override string GetClassNameCore() { return "CardControl"; @@ -42,7 +36,7 @@ public override object GetPattern(PatternInterface patternInterface) protected override AutomationPeer GetLabeledByCore() { - if (this._owner.Header is UIElement element) + if (owner.Header is UIElement element) { return CreatePeerForElement(element); } @@ -52,19 +46,19 @@ protected override AutomationPeer GetLabeledByCore() protected override string GetNameCore() { - string result = base.GetNameCore() ?? String.Empty; + var result = base.GetNameCore() ?? string.Empty; - if (result == String.Empty) + if (result == string.Empty) { - result = AutomationProperties.GetName(this._owner); + result = AutomationProperties.GetName(owner); } - if (result == String.Empty && this._owner.Header is DependencyObject d) + if (result == string.Empty && owner.Header is DependencyObject d) { result = AutomationProperties.GetName(d); } - if (result == String.Empty && this._owner.Header is string s) + if (result == string.Empty && owner.Header is string s) { result = s; } diff --git a/source/RevitLookup.UI/ContentDialogService.cs b/source/RevitLookup.UI/ContentDialogService.cs index 238a44972..c0b9e3200 100644 --- a/source/RevitLookup.UI/ContentDialogService.cs +++ b/source/RevitLookup.UI/ContentDialogService.cs @@ -77,4 +77,4 @@ public Task ShowAsync(ContentDialog dialog, CancellationTok return dialog.ShowAsync(cancellationToken); } -} \ No newline at end of file +} diff --git a/source/RevitLookup.UI/Controls/AccessText/AccessText.xaml b/source/RevitLookup.UI/Controls/AccessText/AccessText.xaml new file mode 100644 index 000000000..3e8dde99c --- /dev/null +++ b/source/RevitLookup.UI/Controls/AccessText/AccessText.xaml @@ -0,0 +1,24 @@ + + + + + + + - - - + - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowIndicator.xaml b/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowIndicator.xaml new file mode 100644 index 000000000..77537437e --- /dev/null +++ b/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowIndicator.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowPresenter.cs b/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowPresenter.cs new file mode 100644 index 000000000..b57b34a1e --- /dev/null +++ b/source/RevitLookup.UI/Controls/GridView/GridViewHeaderRowPresenter.cs @@ -0,0 +1,91 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using System.Diagnostics; +using System.Reflection; +using System.Windows.Controls; + +namespace Wpf.Ui.Controls; + +/// +/// Extends , and adds layout support for , which can have and . +/// +public class GridViewHeaderRowPresenter : System.Windows.Controls.GridViewHeaderRowPresenter +{ + public GridViewHeaderRowPresenter() + { + Loaded += OnLoaded; + } + + protected override Size ArrangeOverride(Size arrangeSize) + { + // update the desired width of each column (clamps desiredwidth to MinWidth and MaxWidth) + if (Columns != null) + { + foreach (GridViewColumn column in Columns.OfType()) + { + column.UpdateDesiredWidth(); + } + } + + return base.ArrangeOverride(arrangeSize); + } + + protected override Size MeasureOverride(Size constraint) + { + if (Columns != null) + { + foreach (GridViewColumn column in Columns.OfType()) + { + column.UpdateDesiredWidth(); + } + } + + return base.MeasureOverride(constraint); + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + UpdateIndicatorStyle(); + } + + private void UpdateIndicatorStyle() + { + FieldInfo? indicatorField = typeof(System.Windows.Controls.GridViewHeaderRowPresenter).GetField( + "_indicator", + BindingFlags.NonPublic | BindingFlags.Instance + ); + + if (indicatorField == null) + { + Debug.WriteLine("Failed to get the _indicator field"); + return; + } + + if (indicatorField.GetValue(this) is Separator indicator) + { + indicator.Margin = new Thickness(0); + indicator.Width = 3.0; + + ResourceDictionary resourceDictionary = + new() + { + Source = new Uri( + "pack://application:,,,/RevitLookup.UI;component/Controls/GridView/GridViewHeaderRowIndicator.xaml", + UriKind.Absolute + ) + }; + + if (resourceDictionary["GridViewHeaderRowIndicatorTemplate"] is ControlTemplate template) + { + indicator.Template = template; + } + else + { + Debug.WriteLine("Failed to get the GridViewHeaderRowIndicatorTemplate"); + } + } + } +} diff --git a/source/RevitLookup.UI/Controls/GridView/GridViewRowPresenter.cs b/source/RevitLookup.UI/Controls/GridView/GridViewRowPresenter.cs new file mode 100644 index 000000000..a416b647b --- /dev/null +++ b/source/RevitLookup.UI/Controls/GridView/GridViewRowPresenter.cs @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +// ReSharper disable once CheckNamespace +namespace Wpf.Ui.Controls; + +/// +/// Extends , and adds header row layout support for , which can have and . +/// +public class GridViewRowPresenter : System.Windows.Controls.GridViewRowPresenter +{ + protected override Size ArrangeOverride(Size arrangeSize) + { + // update the desired width of each column (clamps desiredwidth to MinWidth and MaxWidth) + if (Columns != null) + { + foreach (GridViewColumn column in Columns.OfType()) + { + column.UpdateDesiredWidth(); + } + } + + return base.ArrangeOverride(arrangeSize); + } + + protected override Size MeasureOverride(Size constraint) + { + if (Columns != null) + { + foreach (GridViewColumn column in Columns.OfType()) + { + column.UpdateDesiredWidth(); + } + } + + return base.MeasureOverride(constraint); + } +} diff --git a/source/RevitLookup.UI/Controls/HyperlinkButton/HyperlinkButton.cs b/source/RevitLookup.UI/Controls/HyperlinkButton/HyperlinkButton.cs index 1b109dba8..9db3aee49 100644 --- a/source/RevitLookup.UI/Controls/HyperlinkButton/HyperlinkButton.cs +++ b/source/RevitLookup.UI/Controls/HyperlinkButton/HyperlinkButton.cs @@ -13,9 +13,7 @@ namespace Wpf.Ui.Controls; /// public class HyperlinkButton : Wpf.Ui.Controls.Button { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty NavigateUriProperty = DependencyProperty.Register( nameof(NavigateUri), typeof(string), @@ -24,7 +22,7 @@ public class HyperlinkButton : Wpf.Ui.Controls.Button ); /// - /// The URL (or application shortcut) to open. + /// Gets or sets the URL (or application shortcut) to open. /// public string NavigateUri { @@ -49,7 +47,7 @@ protected override void OnClick() ProcessStartInfo sInfo = new(new Uri(NavigateUri).AbsoluteUri) { UseShellExecute = true }; - Process.Start(sInfo); + _ = Process.Start(sInfo); } catch (Exception e) { diff --git a/source/RevitLookup.UI/Controls/IThemeElement.cs b/source/RevitLookup.UI/Controls/IThemeControl.cs similarity index 92% rename from source/RevitLookup.UI/Controls/IThemeElement.cs rename to source/RevitLookup.UI/Controls/IThemeControl.cs index 1c6ec5497..8f15dd435 100644 --- a/source/RevitLookup.UI/Controls/IThemeElement.cs +++ b/source/RevitLookup.UI/Controls/IThemeControl.cs @@ -11,7 +11,7 @@ namespace Wpf.Ui.Controls; public interface IThemeControl { /// - /// The theme is currently set. + /// Gets the theme that is currently set. /// public Appearance.ApplicationTheme ApplicationTheme { get; } } diff --git a/source/RevitLookup.UI/Controls/IconElement/FontIcon.cs b/source/RevitLookup.UI/Controls/IconElement/FontIcon.cs index 91399d684..c9df0c9e4 100644 --- a/source/RevitLookup.UI/Controls/IconElement/FontIcon.cs +++ b/source/RevitLookup.UI/Controls/IconElement/FontIcon.cs @@ -15,39 +15,27 @@ namespace Wpf.Ui.Controls; /// /// Represents an icon that uses a glyph from the specified font. /// -//[ToolboxItem(true)] -//[ToolboxBitmap(typeof(FontIcon), "FontIcon.bmp")] public class FontIcon : IconElement { - #region Static properties - - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register( nameof(FontFamily), typeof(FontFamily), typeof(FontIcon), - new FrameworkPropertyMetadata(SystemFonts.MessageFontFamily, OnFontFamilyChanged) + new FrameworkPropertyMetadata(new FontFamily("Segoe MDL2 Assets"), OnFontFamilyChanged) ); - /// - /// Property for . - /// - public static readonly DependencyProperty FontSizeProperty = TextElement - .FontSizeProperty - .AddOwner( - typeof(FontIcon), - new FrameworkPropertyMetadata( - SystemFonts.MessageFontSize, - FrameworkPropertyMetadataOptions.Inherits, - OnFontSizeChanged - ) - ); + /// Identifies the dependency property. + public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner( + typeof(FontIcon), + new FrameworkPropertyMetadata( + SystemFonts.MessageFontSize, + FrameworkPropertyMetadataOptions.Inherits, + OnFontSizeChanged + ) + ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register( nameof(FontStyle), typeof(FontStyle), @@ -55,9 +43,7 @@ public class FontIcon : IconElement new FrameworkPropertyMetadata(FontStyles.Normal, OnFontStyleChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register( nameof(FontWeight), typeof(FontWeight), @@ -65,9 +51,7 @@ public class FontIcon : IconElement new FrameworkPropertyMetadata(FontWeights.Normal, OnFontWeightChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty GlyphProperty = DependencyProperty.Register( nameof(Glyph), typeof(string), @@ -75,12 +59,9 @@ public class FontIcon : IconElement new FrameworkPropertyMetadata(string.Empty, OnGlyphChanged) ); - #endregion - - #region Properties - /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] [Localizability(LocalizationCategory.Font)] public FontFamily FontFamily { @@ -90,7 +71,8 @@ public FontFamily FontFamily /// [TypeConverter(typeof(FontSizeConverter))] - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] [Localizability(LocalizationCategory.None)] public double FontSize { @@ -99,7 +81,8 @@ public double FontSize } /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public FontStyle FontStyle { get => (FontStyle)GetValue(FontStyleProperty); @@ -107,7 +90,8 @@ public FontStyle FontStyle } /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public FontWeight FontWeight { get => (FontWeight)GetValue(FontWeightProperty); @@ -124,17 +108,15 @@ public string Glyph set => SetValue(GlyphProperty, value); } - #endregion - - protected TextBlock? TextBlock; + protected TextBlock? TextBlock { get; set; } protected override UIElement InitializeChildren() { // if (VisualParent is not null) // { - // FontSize = TextElement.GetFontSize(VisualParent); + // SetCurrentValue(FontSizeProperty, TextElement.GetFontSize(VisualParent)); // } - + // // if (FontSize.Equals(SystemFonts.MessageFontSize)) // { // SetResourceReference(FontSizeProperty, "DefaultIconFontSize"); @@ -155,57 +137,75 @@ protected override UIElement InitializeChildren() Focusable = false, }; - Focusable = false; + SetCurrentValue(FocusableProperty, false); return TextBlock; } - #region Static methods - private static void OnFontFamilyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (FontIcon)d; if (self.TextBlock is null) + { return; + } - self.TextBlock.FontFamily = (FontFamily)e.NewValue; + self.TextBlock.SetCurrentValue( + System.Windows.Controls.TextBlock.FontFamilyProperty, + (FontFamily)e.NewValue + ); } private static void OnFontSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (FontIcon)d; if (self.TextBlock is null) + { return; + } - self.TextBlock.FontSize = (double)e.NewValue; + self.TextBlock.SetCurrentValue( + System.Windows.Controls.TextBlock.FontSizeProperty, + (double)e.NewValue + ); } private static void OnFontStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (FontIcon)d; if (self.TextBlock is null) + { return; + } - self.TextBlock.FontStyle = (FontStyle)e.NewValue; + self.TextBlock.SetCurrentValue( + System.Windows.Controls.TextBlock.FontStyleProperty, + (FontStyle)e.NewValue + ); } private static void OnFontWeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (FontIcon)d; if (self.TextBlock is null) + { return; + } - self.TextBlock.FontWeight = (FontWeight)e.NewValue; + self.TextBlock.SetCurrentValue( + System.Windows.Controls.TextBlock.FontWeightProperty, + (FontWeight)e.NewValue + ); } private static void OnGlyphChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var self = (FontIcon)d; if (self.TextBlock is null) + { return; + } - self.TextBlock.Text = (string)e.NewValue; + self.TextBlock.SetCurrentValue(System.Windows.Controls.TextBlock.TextProperty, (string)e.NewValue); } - - #endregion } diff --git a/source/RevitLookup.UI/Controls/IconElement/IconElement.cs b/source/RevitLookup.UI/Controls/IconElement/IconElement.cs index 3eb2ec92a..d5d13e18a 100644 --- a/source/RevitLookup.UI/Controls/IconElement/IconElement.cs +++ b/source/RevitLookup.UI/Controls/IconElement/IconElement.cs @@ -19,27 +19,25 @@ public abstract class IconElement : FrameworkElement static IconElement() { FocusableProperty.OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false)); - KeyboardNavigation - .IsTabStopProperty - .OverrideMetadata(typeof(IconElement), new FrameworkPropertyMetadata(false)); - } - - /// - /// Property for . - /// - public static readonly DependencyProperty ForegroundProperty = TextElement - .ForegroundProperty - .AddOwner( + KeyboardNavigation.IsTabStopProperty.OverrideMetadata( typeof(IconElement), - new FrameworkPropertyMetadata( - SystemColors.ControlTextBrush, - FrameworkPropertyMetadataOptions.Inherits, - static (d, args) => ((IconElement)d).OnForegroundPropertyChanged(args) - ) + new FrameworkPropertyMetadata(false) ); + } + + /// Identifies the dependency property. + public static readonly DependencyProperty ForegroundProperty = TextElement.ForegroundProperty.AddOwner( + typeof(IconElement), + new FrameworkPropertyMetadata( + SystemColors.ControlTextBrush, + FrameworkPropertyMetadataOptions.Inherits, + static (d, args) => ((IconElement)d).OnForegroundChanged(args) + ) + ); /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public Brush Foreground { get => (Brush)GetValue(ForegroundProperty); @@ -50,31 +48,30 @@ public Brush Foreground private Grid? _layoutRoot; - #region Protected methods - protected abstract UIElement InitializeChildren(); - protected virtual void OnForegroundPropertyChanged(DependencyPropertyChangedEventArgs args) { } - - #endregion - - #region Layout methods + protected virtual void OnForegroundChanged(DependencyPropertyChangedEventArgs args) { } private void EnsureLayoutRoot() { if (_layoutRoot != null) + { return; + } _layoutRoot = new Grid { Background = Brushes.Transparent, SnapsToDevicePixels = true, }; - _layoutRoot.Children.Add(InitializeChildren()); + _ = _layoutRoot.Children.Add(InitializeChildren()); + AddVisualChild(_layoutRoot); } protected override Visual GetVisualChild(int index) { if (index != 0) - throw new ArgumentOutOfRangeException(nameof(index)); + { + throw new ArgumentOutOfRangeException(nameof(index), "IconElement should have only 1 child"); + } EnsureLayoutRoot(); return _layoutRoot!; @@ -92,9 +89,27 @@ protected override Size ArrangeOverride(Size finalSize) { EnsureLayoutRoot(); - _layoutRoot!.Arrange(new Rect(new Point(), finalSize)); + _layoutRoot!.Arrange(new Rect(default, finalSize)); return finalSize; } - #endregion + /// + /// Coerces the value of an Icon dependency property, allowing the use of either IconElement or IconSourceElement. + /// + /// The dependency object (unused). + /// The value to be coerced. + /// An IconElement, either directly or derived from an IconSourceElement. + public static object? Coerce(DependencyObject _, object? baseValue) + { + return baseValue switch + { + IconSourceElement iconSourceElement => iconSourceElement.CreateIconElement(), + IconElement or null => baseValue, + _ + => throw new ArgumentException( + message: $"Expected either '{typeof(IconSourceElement)}' or '{typeof(IconElement)}' but got '{baseValue.GetType()}'.", + paramName: nameof(baseValue) + ) + }; + } } diff --git a/source/RevitLookup.UI/Controls/IconElement/IconElementConverter.cs b/source/RevitLookup.UI/Controls/IconElement/IconElementConverter.cs index 30b962965..ab04650c9 100644 --- a/source/RevitLookup.UI/Controls/IconElement/IconElementConverter.cs +++ b/source/RevitLookup.UI/Controls/IconElement/IconElementConverter.cs @@ -3,23 +3,25 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using Wpf.Ui.Extensions; - // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; /// -/// Tries to convert and to . +/// Tries to convert and to . /// public class IconElementConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { if (sourceType == typeof(SymbolRegular)) + { return true; + } if (sourceType == typeof(SymbolFilled)) + { return true; + } return false; } diff --git a/source/RevitLookup.UI/Controls/IconElement/IconSourceElement.cs b/source/RevitLookup.UI/Controls/IconElement/IconSourceElement.cs index 425a92c1a..19c349db4 100644 --- a/source/RevitLookup.UI/Controls/IconElement/IconSourceElement.cs +++ b/source/RevitLookup.UI/Controls/IconElement/IconSourceElement.cs @@ -4,7 +4,6 @@ // All Rights Reserved. using System.Windows.Markup; -using Wpf.Ui.Converters; // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -15,9 +14,7 @@ namespace Wpf.Ui.Controls; [ContentProperty(nameof(IconSource))] public class IconSourceElement : IconElement { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IconSourceProperty = DependencyProperty.Register( nameof(IconSource), typeof(IconSource), @@ -30,13 +27,18 @@ public class IconSourceElement : IconElement /// public IconSource? IconSource { - get => (IconSource)GetValue(IconSourceProperty); + get => (IconSource?)GetValue(IconSourceProperty); set => SetValue(IconSourceProperty, value); } protected override UIElement InitializeChildren() { - //TODO come up with an elegant solution - throw new InvalidOperationException($"Use {nameof(IconSourceElementConverter)} class."); + // TODO: Come up with an elegant solution + throw new InvalidOperationException($"Use {nameof(CreateIconElement)}"); + } + + public IconElement? CreateIconElement() + { + return IconSource?.CreateIconElement(); } } diff --git a/source/RevitLookup.UI/Controls/IconElement/ImageIcon.cs b/source/RevitLookup.UI/Controls/IconElement/ImageIcon.cs index d6e0ab9ba..970eeb69f 100644 --- a/source/RevitLookup.UI/Controls/IconElement/ImageIcon.cs +++ b/source/RevitLookup.UI/Controls/IconElement/ImageIcon.cs @@ -11,9 +11,7 @@ namespace Wpf.Ui.Controls; /// public class ImageIcon : IconElement { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( nameof(Source), typeof(ImageSource), @@ -21,7 +19,7 @@ public class ImageIcon : IconElement new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, - OnSourcePropertyChanged + OnSourceChanged ) ); @@ -30,11 +28,11 @@ public class ImageIcon : IconElement /// public ImageSource? Source { - get => (ImageSource)GetValue(SourceProperty); + get => (ImageSource?)GetValue(SourceProperty); set => SetValue(SourceProperty, value); } - protected System.Windows.Controls.Image? Image; + protected System.Windows.Controls.Image? Image { get; set; } protected override UIElement InitializeChildren() { @@ -43,12 +41,15 @@ protected override UIElement InitializeChildren() return Image; } - private static void OnSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - var self = (ImageIcon)d; + ImageIcon self = (ImageIcon)d; + if (self.Image is null) + { return; + } - self.Image.Source = (ImageSource)e.NewValue; + self.Image.SetCurrentValue(System.Windows.Controls.Image.SourceProperty, (ImageSource?)e.NewValue); } } diff --git a/source/RevitLookup.UI/Controls/IconElement/SymbolIcon.cs b/source/RevitLookup.UI/Controls/IconElement/SymbolIcon.cs index 14a48f70c..7cd3189b8 100644 --- a/source/RevitLookup.UI/Controls/IconElement/SymbolIcon.cs +++ b/source/RevitLookup.UI/Controls/IconElement/SymbolIcon.cs @@ -3,21 +3,15 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using Wpf.Ui.Extensions; - // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; /// /// Represents a text element containing an icon glyph. /// -//[ToolboxItem(true)] -//[ToolboxBitmap(typeof(SymbolIcon), "SymbolIcon.bmp")] public class SymbolIcon : FontIcon { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register( nameof(Symbol), typeof(SymbolRegular), @@ -25,9 +19,7 @@ public class SymbolIcon : FontIcon new PropertyMetadata(SymbolRegular.Empty, static (o, _) => ((SymbolIcon)o).OnGlyphChanged()) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FilledProperty = DependencyProperty.Register( nameof(Filled), typeof(bool), @@ -45,7 +37,7 @@ public SymbolRegular Symbol } /// - /// Defines whether or not we should use the . + /// Gets or sets a value indicating whether or not we should use the . /// public bool Filled { @@ -72,9 +64,13 @@ protected override void OnInitialized(EventArgs e) private void OnGlyphChanged() { if (Filled) - Glyph = Symbol.Swap().GetString(); + { + SetCurrentValue(GlyphProperty, Symbol.Swap().GetString()); + } else - Glyph = Symbol.GetString(); + { + SetCurrentValue(GlyphProperty, Symbol.GetString()); + } } private void SetFontReference() diff --git a/source/RevitLookup.UI/Controls/IconSource/FontIconSource.cs b/source/RevitLookup.UI/Controls/IconSource/FontIconSource.cs index 46110ba1f..74d9d14ff 100644 --- a/source/RevitLookup.UI/Controls/IconSource/FontIconSource.cs +++ b/source/RevitLookup.UI/Controls/IconSource/FontIconSource.cs @@ -13,9 +13,7 @@ namespace Wpf.Ui.Controls; /// public class FontIconSource : IconSource { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontFamilyProperty = DependencyProperty.Register( nameof(FontFamily), typeof(FontFamily), @@ -23,9 +21,7 @@ public class FontIconSource : IconSource new PropertyMetadata(SystemFonts.MessageFontFamily) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register( nameof(FontSize), typeof(double), @@ -33,9 +29,7 @@ public class FontIconSource : IconSource new PropertyMetadata(SystemFonts.MessageFontSize) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register( nameof(FontStyle), typeof(FontStyle), @@ -43,9 +37,7 @@ public class FontIconSource : IconSource new PropertyMetadata(FontStyles.Normal) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register( nameof(FontWeight), typeof(FontWeight), @@ -53,9 +45,7 @@ public class FontIconSource : IconSource new PropertyMetadata(FontWeights.Normal) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty GlyphProperty = DependencyProperty.Register( nameof(Glyph), typeof(string), @@ -103,7 +93,7 @@ public string Glyph public override IconElement CreateIconElement() { - FontIcon fontIcon = new FontIcon() { Glyph = Glyph }; + var fontIcon = new FontIcon() { Glyph = Glyph }; if (!Equals(FontFamily, SystemFonts.MessageFontFamily)) { diff --git a/source/RevitLookup.UI/Controls/IconSource/IconSource.cs b/source/RevitLookup.UI/Controls/IconSource/IconSource.cs index fdf5b588a..dd07efcd3 100644 --- a/source/RevitLookup.UI/Controls/IconSource/IconSource.cs +++ b/source/RevitLookup.UI/Controls/IconSource/IconSource.cs @@ -13,9 +13,7 @@ namespace Wpf.Ui.Controls; /// public abstract class IconSource : DependencyObject { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register( nameof(Foreground), typeof(Brush), @@ -23,9 +21,7 @@ public abstract class IconSource : DependencyObject new FrameworkPropertyMetadata(SystemColors.ControlTextBrush) ); - /// /// - /// public Brush Foreground { get => (Brush)GetValue(ForegroundProperty); diff --git a/source/RevitLookup.UI/Controls/IconSource/SymbolIconSource.cs b/source/RevitLookup.UI/Controls/IconSource/SymbolIconSource.cs index 6a865d18a..95a548503 100644 --- a/source/RevitLookup.UI/Controls/IconSource/SymbolIconSource.cs +++ b/source/RevitLookup.UI/Controls/IconSource/SymbolIconSource.cs @@ -13,9 +13,7 @@ namespace Wpf.Ui.Controls; /// public class SymbolIconSource : IconSource { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register( nameof(FontSize), typeof(double), @@ -23,9 +21,7 @@ public class SymbolIconSource : IconSource new PropertyMetadata(SystemFonts.MessageFontSize) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontStyleProperty = DependencyProperty.Register( nameof(FontStyle), typeof(FontStyle), @@ -33,9 +29,7 @@ public class SymbolIconSource : IconSource new PropertyMetadata(FontStyles.Normal) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontWeightProperty = DependencyProperty.Register( nameof(FontWeight), typeof(FontWeight), @@ -43,9 +37,7 @@ public class SymbolIconSource : IconSource new PropertyMetadata(FontWeights.Normal) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register( nameof(Symbol), typeof(SymbolRegular), @@ -53,9 +45,7 @@ public class SymbolIconSource : IconSource new PropertyMetadata(SymbolRegular.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FilledProperty = DependencyProperty.Register( nameof(Filled), typeof(bool), @@ -94,7 +84,7 @@ public SymbolRegular Symbol } /// - /// Defines whether or not we should use the . + /// Gets or sets a value indicating whether or not we should use the . /// public bool Filled { diff --git a/source/RevitLookup.UI/Controls/Image/Image.cs b/source/RevitLookup.UI/Controls/Image/Image.cs index 5f62288fe..23c49cd78 100644 --- a/source/RevitLookup.UI/Controls/Image/Image.cs +++ b/source/RevitLookup.UI/Controls/Image/Image.cs @@ -13,11 +13,7 @@ namespace Wpf.Ui.Controls; /// public class Image : Control { - #region DependencyPropreties - /// - /// Gets/Sets the Source on this Image. - /// The Source property is the ImageSource that holds the actual image drawn. - /// + /// Identifies the dependency property. public static readonly DependencyProperty SourceProperty = DependencyProperty.Register( nameof(Source), typeof(ImageSource), @@ -31,9 +27,7 @@ public class Image : Control null ); - /// - /// DependencyProperty for CornerRadius property. - /// + /// Identifies the dependency property. public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( nameof(CornerRadius), typeof(CornerRadius), @@ -41,9 +35,7 @@ public class Image : Control new PropertyMetadata(new CornerRadius(0), new PropertyChangedCallback(OnCornerRadiusChanged)) ); - /// - /// DependencyProperty for StretchDirection property. - /// + /// Identifies the dependency property. /// public static readonly DependencyProperty StretchProperty = DependencyProperty.Register( nameof(Stretch), @@ -56,9 +48,7 @@ public class Image : Control null ); - /// - /// DependencyProperty for Stretch property. - /// + /// Identifies the dependency property. public static readonly DependencyProperty StretchDirectionProperty = DependencyProperty.Register( nameof(StretchDirection), typeof(StretchDirection), @@ -70,9 +60,7 @@ public class Image : Control null ); - /// - /// DependencyPropertyKey for InnerCornerRadius property. - /// + /// Identifies the dependency property. public static readonly DependencyPropertyKey InnerCornerRadiusPropertyKey = DependencyProperty.RegisterReadOnly( nameof(InnerCornerRadius), @@ -81,26 +69,22 @@ public class Image : Control new PropertyMetadata(new CornerRadius(0)) ); - /// - /// DependencyProperty for InnerCornerRadius property. - /// + /// Identifies the dependency property. public static readonly DependencyProperty InnerCornerRadiusProperty = InnerCornerRadiusPropertyKey.DependencyProperty; - #endregion - #region Propreties /// - /// Gets/Sets the Source on this Image. + /// Gets or sets the Source on this Image. /// The Source property is the ImageSource that holds the actual image drawn. /// - public ImageSource Source + public ImageSource? Source { - get => (ImageSource)GetValue(SourceProperty); + get => (ImageSource?)GetValue(SourceProperty); set => SetValue(SourceProperty, value); } /// - /// Gets/Sets the Stretch on this Image. + /// Gets or sets the Stretch on this Image. /// The Stretch property determines how large the Image will be drawn. /// public Stretch Stretch @@ -110,7 +94,7 @@ public Stretch Stretch } /// - /// Gets/Sets the stretch direction of the Viewbox, which determines the restrictions on + /// Gets or sets the stretch direction of the Viewbox, which determines the restrictions on /// scaling that are applied to the content inside the Viewbox. For instance, this property /// can be used to prevent the content from being smaller than its native size or larger than /// its native size. @@ -122,7 +106,7 @@ public StretchDirection StretchDirection } /// - /// The CornerRadius property allows users to control the roundness of the corners independently by + /// Gets or sets the CornerRadius property allows users to control the roundness of the corners independently by /// setting a radius value for each corner. Radius values that are too large are scaled so that they /// smoothly blend from corner to corner. /// @@ -133,27 +117,24 @@ public CornerRadius CornerRadius } /// - /// The CornerRadius for the inner image's Mask. + /// Gets the CornerRadius for the inner image's Mask. /// internal CornerRadius InnerCornerRadius => (CornerRadius)GetValue(InnerCornerRadiusProperty); - #endregion - #region Methods private static void OnCornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var thickness = (Thickness)d.GetValue(BorderThicknessProperty); var outerRarius = (CornerRadius)e.NewValue; - //Inner radius = Outer radius - thickenss/2 + // Inner radius = Outer radius - thickenss/2 d.SetValue( InnerCornerRadiusPropertyKey, new CornerRadius( - topLeft: Math.Max(0, (int)Math.Round(outerRarius.TopLeft - thickness.Left / 2, 0)), - topRight: Math.Max(0, (int)Math.Round(outerRarius.TopRight - thickness.Top / 2, 0)), - bottomRight: Math.Max(0, (int)Math.Round(outerRarius.BottomRight - thickness.Right / 2, 0)), - bottomLeft: Math.Max(0, (int)Math.Round(outerRarius.BottomLeft - thickness.Bottom / 2, 0)) + topLeft: Math.Max(0, (int)Math.Round(outerRarius.TopLeft - (thickness.Left / 2), 0)), + topRight: Math.Max(0, (int)Math.Round(outerRarius.TopRight - (thickness.Top / 2), 0)), + bottomRight: Math.Max(0, (int)Math.Round(outerRarius.BottomRight - (thickness.Right / 2), 0)), + bottomLeft: Math.Max(0, (int)Math.Round(outerRarius.BottomLeft - (thickness.Bottom / 2), 0)) ) ); } - #endregion } diff --git a/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.cs b/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.cs index b1432d12b..df893a752 100644 --- a/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.cs +++ b/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.cs @@ -3,25 +3,19 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using Wpf.Ui.Converters; - namespace Wpf.Ui.Controls; public class InfoBadge : System.Windows.Controls.Control { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IconProperty = DependencyProperty.Register( nameof(Icon), typeof(IconElement), typeof(InfoBadge), - new PropertyMetadata(null, null, IconSourceElementConverter.ConvertToIconElement) + new PropertyMetadata(null, null, IconElement.Coerce) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SeverityProperty = DependencyProperty.Register( nameof(Severity), typeof(InfoBadgeSeverity), @@ -29,9 +23,7 @@ public class InfoBadge : System.Windows.Controls.Control new PropertyMetadata(InfoBadgeSeverity.Informational) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( nameof(Value), typeof(string), @@ -39,18 +31,14 @@ public class InfoBadge : System.Windows.Controls.Control new PropertyMetadata(string.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( nameof(CornerRadius), typeof(CornerRadius), typeof(InfoBadge), - (PropertyMetadata) new FrameworkPropertyMetadata( - (object)new CornerRadius(8), - FrameworkPropertyMetadataOptions.AffectsMeasure - | FrameworkPropertyMetadataOptions.AffectsRender + new CornerRadius(8), + FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender ) ); @@ -62,6 +50,7 @@ public InfoBadgeSeverity Severity get => (InfoBadgeSeverity)GetValue(SeverityProperty); set => SetValue(SeverityProperty, value); } + /// /// Gets or sets the title of the . /// @@ -76,17 +65,18 @@ public string Value /// public CornerRadius CornerRadius { - get => (CornerRadius)GetValue(ValueProperty); - set => SetValue(ValueProperty, value); + get => (CornerRadius)GetValue(CornerRadiusProperty); + set => SetValue(CornerRadiusProperty, value); } /// /// Gets or sets displayed . /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public IconElement? Icon { - get => (IconElement)GetValue(IconProperty); + get => (IconElement?)GetValue(IconProperty); set => SetValue(IconProperty, value); } } diff --git a/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.xaml b/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.xaml index 6cfd53180..3a2d3f387 100644 --- a/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.xaml +++ b/source/RevitLookup.UI/Controls/InfoBadge/InfoBadge.xaml @@ -25,8 +25,8 @@ Critical = 4 -} \ No newline at end of file +} diff --git a/source/RevitLookup.UI/Controls/InfoBar/InfoBar.cs b/source/RevitLookup.UI/Controls/InfoBar/InfoBar.cs index 957edef9a..80de344f4 100644 --- a/source/RevitLookup.UI/Controls/InfoBar/InfoBar.cs +++ b/source/RevitLookup.UI/Controls/InfoBar/InfoBar.cs @@ -17,9 +17,7 @@ namespace Wpf.Ui.Controls; /// public class InfoBar : System.Windows.Controls.ContentControl { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsClosableProperty = DependencyProperty.Register( nameof(IsClosable), typeof(bool), @@ -27,9 +25,7 @@ public class InfoBar : System.Windows.Controls.ContentControl new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register( nameof(IsOpen), typeof(bool), @@ -37,29 +33,23 @@ public class InfoBar : System.Windows.Controls.ContentControl new PropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( nameof(Title), typeof(string), typeof(InfoBar), - new PropertyMetadata(String.Empty) + new PropertyMetadata(string.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty MessageProperty = DependencyProperty.Register( nameof(Message), typeof(string), typeof(InfoBar), - new PropertyMetadata(String.Empty) + new PropertyMetadata(string.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SeverityProperty = DependencyProperty.Register( nameof(Severity), typeof(InfoBarSeverity), @@ -67,9 +57,7 @@ public class InfoBar : System.Windows.Controls.ContentControl new PropertyMetadata(InfoBarSeverity.Informational) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register( nameof(TemplateButtonCommand), typeof(IRelayCommand), @@ -78,8 +66,7 @@ public class InfoBar : System.Windows.Controls.ContentControl ); /// - /// Gets or sets a value that indicates whether the user can close the - /// . Defaults to true. + /// Gets or sets a value indicating whether the user can close the . Defaults to true. /// public bool IsClosable { @@ -88,8 +75,7 @@ public bool IsClosable } /// - /// Gets or sets a value that indicates whether the - /// is open. + /// Gets or sets a value indicating whether the is open. /// public bool IsOpen { @@ -132,9 +118,14 @@ public InfoBarSeverity Severity /// public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty); - /// + /// + /// Initializes a new instance of the class. + /// public InfoBar() { - SetValue(TemplateButtonCommandProperty, new RelayCommand(o => IsOpen = false)); + SetValue( + TemplateButtonCommandProperty, + new RelayCommand(_ => SetCurrentValue(IsOpenProperty, false)) + ); } } diff --git a/source/RevitLookup.UI/Controls/InfoBar/InfoBar.xaml b/source/RevitLookup.UI/Controls/InfoBar/InfoBar.xaml index 44da6f3f1..2c24495e9 100644 --- a/source/RevitLookup.UI/Controls/InfoBar/InfoBar.xaml +++ b/source/RevitLookup.UI/Controls/InfoBar/InfoBar.xaml @@ -53,7 +53,7 @@ - + + + + + - + - + diff --git a/source/RevitLookup.UI/Controls/ItemRange.cs b/source/RevitLookup.UI/Controls/ItemRange.cs index 9c8f29b74..96f4e646d 100644 --- a/source/RevitLookup.UI/Controls/ItemRange.cs +++ b/source/RevitLookup.UI/Controls/ItemRange.cs @@ -3,10 +3,11 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. -// https://github.com/sbaeumlisberger/VirtualizingWrapPanel -// Copyright (C) S. Bäumlisberger -// All Rights Reserved. +/* Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. + https://github.com/sbaeumlisberger/VirtualizingWrapPanel + + Copyright (C) S. Bäumlisberger + All Rights Reserved. */ namespace Wpf.Ui.Controls; @@ -14,9 +15,10 @@ namespace Wpf.Ui.Controls; /// Items range. /// Based on . /// -public struct ItemRange +public readonly struct ItemRange { public int StartIndex { get; } + public int EndIndex { get; } public ItemRange(int startIndex, int endIndex) @@ -26,8 +28,5 @@ public ItemRange(int startIndex, int endIndex) EndIndex = endIndex; } - public bool Contains(int itemIndex) - { - return itemIndex >= StartIndex && itemIndex <= EndIndex; - } + public readonly bool Contains(int itemIndex) => itemIndex >= StartIndex && itemIndex <= EndIndex; } diff --git a/source/RevitLookup.UI/Controls/ListView/ListView.cs b/source/RevitLookup.UI/Controls/ListView/ListView.cs new file mode 100644 index 000000000..ef2b44a30 --- /dev/null +++ b/source/RevitLookup.UI/Controls/ListView/ListView.cs @@ -0,0 +1,114 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.Controls; + +/// +/// Extends , and adds customized support or . +/// +/// +/// +/// <ui:ListView ItemsSource="{Binding ...}" > +/// <ui:ListView.View> +/// <ui:GridView> +/// <GridViewColumn +/// DisplayMemberBinding="{Binding FirstName}" +/// Header="First Name" /> +/// <GridViewColumn +/// DisplayMemberBinding="{Binding LastName}" +/// Header="Last Name" /> +/// </ui:GridView> +/// </ui:ListView.View> +/// </ui:ListView> +/// +/// +public class ListView : System.Windows.Controls.ListView +{ + /// Identifies the dependency property. + public static readonly DependencyProperty ViewStateProperty = DependencyProperty.Register( + nameof(ViewState), + typeof(ListViewViewState), + typeof(ListView), + new FrameworkPropertyMetadata(ListViewViewState.Default, OnViewStateChanged) + ); + + /// + /// Gets or sets the view state of the , enabling custom logic based on the current view. + /// + /// The current view state of the . + public ListViewViewState ViewState + { + get => (ListViewViewState)GetValue(ViewStateProperty); + set => SetValue(ViewStateProperty, value); + } + + private static void OnViewStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not ListView self) + { + return; + } + + self.OnViewStateChanged(e); + } + + protected virtual void OnViewStateChanged(DependencyPropertyChangedEventArgs e) + { + // Hook for derived classes to react to ViewState property changes + } + + public ListView() + { + Loaded += OnLoaded; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + Loaded -= OnLoaded; // prevent memory leaks + + // Setup initial ViewState and hook into View property changes + var descriptor = DependencyPropertyDescriptor.FromProperty( + System.Windows.Controls.ListView.ViewProperty, + typeof(System.Windows.Controls.ListView) + ); + descriptor?.AddValueChanged(this, OnViewPropertyChanged); + UpdateViewState(); // set the initial state + } + + private void OnViewPropertyChanged(object? sender, EventArgs e) + { + UpdateViewState(); + } + + private void UpdateViewState() + { + ListViewViewState viewState = View switch + { + System.Windows.Controls.GridView => ListViewViewState.GridView, + null => ListViewViewState.Default, + _ => ListViewViewState.Default + }; + + SetCurrentValue(ViewStateProperty, viewState); + } + + static ListView() + { + DefaultStyleKeyProperty.OverrideMetadata( + typeof(ListView), + new FrameworkPropertyMetadata(typeof(ListView)) + ); + } + + protected override DependencyObject GetContainerForItemOverride() + { + return new ListViewItem(); + } + + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is ListViewItem; + } +} diff --git a/source/RevitLookup.UI/Controls/ListView/ListView.xaml b/source/RevitLookup.UI/Controls/ListView/ListView.xaml index 9001b6a97..6e6eb9711 100644 --- a/source/RevitLookup.UI/Controls/ListView/ListView.xaml +++ b/source/RevitLookup.UI/Controls/ListView/ListView.xaml @@ -10,63 +10,160 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:Wpf.Ui.Controls"> - - - + + + FontSize="16" + KeyboardNavigation.IsTabStop="False" /> + + diff --git a/source/RevitLookup.UI/Controls/Menu/MenuLoader.xaml.cs b/source/RevitLookup.UI/Controls/Menu/MenuLoader.xaml.cs new file mode 100644 index 000000000..409c4f46d --- /dev/null +++ b/source/RevitLookup.UI/Controls/Menu/MenuLoader.xaml.cs @@ -0,0 +1,40 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using System.Reflection; + +namespace Wpf.Ui.Controls; + +/// +/// Changes readonly field value of to false. +/// +public partial class MenuLoader : ResourceDictionary +{ + /// + /// Initializes a new instance of the class. + /// + /// + /// Sets menu alignment on initialization. + /// + public MenuLoader() + { + MenuLoader.Initialize(); + } + + private static void Initialize() + { + if (!SystemParameters.MenuDropAlignment) + { + return; + } + + FieldInfo? fieldInfo = typeof(SystemParameters).GetField( + "_menuDropAlignment", + BindingFlags.NonPublic | BindingFlags.Static + ); + + fieldInfo?.SetValue(null, false); + } +} diff --git a/source/RevitLookup.UI/Controls/MessageBox/MessageBox.cs b/source/RevitLookup.UI/Controls/MessageBox/MessageBox.cs index 3978011c5..1da1681f2 100644 --- a/source/RevitLookup.UI/Controls/MessageBox/MessageBox.cs +++ b/source/RevitLookup.UI/Controls/MessageBox/MessageBox.cs @@ -3,9 +3,13 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. +using System.Reflection; using Wpf.Ui.Input; using Wpf.Ui.Interop; using Size = System.Windows.Size; +#if NET8_0_OR_GREATER +using System.Runtime.CompilerServices; +#endif // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -13,15 +17,9 @@ namespace Wpf.Ui.Controls; /// /// Customized window for notifications. /// -//[ToolboxItem(true)] -//[ToolboxBitmap(typeof(MessageBox), "MessageBox.bmp")] public class MessageBox : System.Windows.Window { - #region Static properties - - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ShowTitleProperty = DependencyProperty.Register( nameof(ShowTitle), typeof(bool), @@ -29,9 +27,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PrimaryButtonTextProperty = DependencyProperty.Register( nameof(PrimaryButtonText), typeof(string), @@ -39,9 +35,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(string.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SecondaryButtonTextProperty = DependencyProperty.Register( nameof(SecondaryButtonText), typeof(string), @@ -49,9 +43,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(string.Empty) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CloseButtonTextProperty = DependencyProperty.Register( nameof(CloseButtonText), typeof(string), @@ -59,39 +51,31 @@ public class MessageBox : System.Windows.Window new PropertyMetadata("Close") ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PrimaryButtonIconProperty = DependencyProperty.Register( nameof(PrimaryButtonIcon), - typeof(SymbolRegular), + typeof(IconElement), typeof(MessageBox), - new PropertyMetadata(SymbolRegular.Empty) + new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SecondaryButtonIconProperty = DependencyProperty.Register( nameof(SecondaryButtonIcon), - typeof(SymbolRegular), + typeof(IconElement), typeof(MessageBox), - new PropertyMetadata(SymbolRegular.Empty) + new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CloseButtonIconProperty = DependencyProperty.Register( nameof(CloseButtonIcon), - typeof(SymbolRegular), + typeof(IconElement), typeof(MessageBox), - new PropertyMetadata(SymbolRegular.Empty) + new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PrimaryButtonAppearanceProperty = DependencyProperty.Register( nameof(PrimaryButtonAppearance), typeof(ControlAppearance), @@ -99,9 +83,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(ControlAppearance.Primary) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SecondaryButtonAppearanceProperty = DependencyProperty.Register( nameof(SecondaryButtonAppearance), typeof(ControlAppearance), @@ -109,9 +91,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(ControlAppearance.Secondary) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CloseButtonAppearanceProperty = DependencyProperty.Register( nameof(CloseButtonAppearance), typeof(ControlAppearance), @@ -119,9 +99,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(ControlAppearance.Secondary) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsPrimaryButtonEnabledProperty = DependencyProperty.Register( nameof(IsPrimaryButtonEnabled), typeof(bool), @@ -129,9 +107,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsSecondaryButtonEnabledProperty = DependencyProperty.Register( nameof(IsSecondaryButtonEnabled), typeof(bool), @@ -139,9 +115,7 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register( nameof(TemplateButtonCommand), typeof(IRelayCommand), @@ -149,12 +123,8 @@ public class MessageBox : System.Windows.Window new PropertyMetadata(null) ); - #endregion - - #region Properties - /// - /// Gets or sets a value that determines whether to show the in . + /// Gets or sets a value indicating whether to show the in . /// public bool ShowTitle { @@ -192,27 +162,27 @@ public string CloseButtonText /// /// Gets or sets the on the primary button /// - public SymbolRegular PrimaryButtonIcon + public IconElement? PrimaryButtonIcon { - get => (SymbolRegular)GetValue(PrimaryButtonIconProperty); + get => (IconElement?)GetValue(PrimaryButtonIconProperty); set => SetValue(PrimaryButtonIconProperty, value); } /// /// Gets or sets the on the secondary button /// - public SymbolRegular SecondaryButtonIcon + public IconElement? SecondaryButtonIcon { - get => (SymbolRegular)GetValue(SecondaryButtonIconProperty); + get => (IconElement?)GetValue(SecondaryButtonIconProperty); set => SetValue(SecondaryButtonIconProperty, value); } /// /// Gets or sets the on the close button /// - public SymbolRegular CloseButtonIcon + public IconElement? CloseButtonIcon { - get => (SymbolRegular)GetValue(CloseButtonIconProperty); + get => (IconElement?)GetValue(CloseButtonIconProperty); set => SetValue(CloseButtonIconProperty, value); } @@ -244,7 +214,7 @@ public ControlAppearance CloseButtonAppearance } /// - /// Gets or sets whether the primary button is enabled. + /// Gets or sets a value indicating whether the primary button is enabled. /// public bool IsSecondaryButtonEnabled { @@ -253,7 +223,7 @@ public bool IsSecondaryButtonEnabled } /// - /// Gets or sets whether the secondary button is enabled. + /// Gets or sets a value indicating whether the secondary button is enabled. /// public bool IsPrimaryButtonEnabled { @@ -262,11 +232,16 @@ public bool IsPrimaryButtonEnabled } /// - /// Command triggered after clicking the button on the Footer. + /// Gets the command triggered after clicking the button on the Footer. /// public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty); - #endregion +#if !NET8_0_OR_GREATER + private static readonly PropertyInfo CanCenterOverWPFOwnerPropertyInfo = typeof(Window).GetProperty( + "CanCenterOverWPFOwner", + BindingFlags.NonPublic | BindingFlags.Instance + )!; +#endif /// /// Initializes a new instance of the class. @@ -285,7 +260,7 @@ public MessageBox() }; } - protected TaskCompletionSource? Tcs; + protected TaskCompletionSource? Tcs { get; set; } [Obsolete($"Use {nameof(ShowDialogAsync)} instead")] public new void Show() @@ -309,7 +284,7 @@ public MessageBox() /// Displays a message box /// /// - /// + /// Thrown if the operation is canceled. public async Task ShowDialogAsync( bool showAsDialog = true, CancellationToken cancellationToken = default @@ -326,9 +301,13 @@ public async Task ShowDialogAsync( RemoveTitleBarAndApplyMica(); if (showAsDialog) + { base.ShowDialog(); + } else + { base.Show(); + } return await Tcs.Task; } @@ -350,22 +329,60 @@ protected virtual void OnLoaded() var rootElement = (UIElement)GetVisualChild(0)!; ResizeToContentSize(rootElement); - CenterWindowOnScreen(); + + switch (WindowStartupLocation) + { + case WindowStartupLocation.Manual: + case WindowStartupLocation.CenterScreen: + CenterWindowOnScreen(); + break; + case WindowStartupLocation.CenterOwner: + if ( + !CanCenterOverWPFOwner() + || Owner.WindowState is WindowState.Maximized or WindowState.Minimized + ) + { + CenterWindowOnScreen(); + } + else + { + CenterWindowOnOwner(); + } + + break; + default: + throw new InvalidOperationException(); + } } + // CanCenterOverWPFOwner property see https://source.dot.net/#PresentationFramework/System/Windows/Window.cs,e679e433777b21b8 + private bool CanCenterOverWPFOwner() + { +#if NET8_0_OR_GREATER + return CanCenterOverWPFOwnerAccessor(this); +#else + return (bool)CanCenterOverWPFOwnerPropertyInfo.GetValue(this)!; +#endif + } + +#if NET8_0_OR_GREATER + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_CanCenterOverWPFOwner")] + private static extern bool CanCenterOverWPFOwnerAccessor(Window w); +#endif + /// - /// Sets Width and Height + /// Resizes the MessageBox to fit the content's size, including margins. /// - /// + /// The root element of the MessageBox protected virtual void ResizeToContentSize(UIElement rootElement) { Size desiredSize = rootElement.DesiredSize; - //left and right margin + // left and right margin const double margin = 12.0 * 2; - Width = desiredSize.Width + margin; - Height = desiredSize.Height; + SetCurrentValue(WidthProperty, desiredSize.Width + margin); + SetCurrentValue(HeightProperty, desiredSize.Height); ResizeWidth(rootElement); ResizeHeight(rootElement); @@ -376,26 +393,35 @@ protected override void OnClosing(CancelEventArgs e) base.OnClosing(e); if (e.Cancel) + { return; + } - Tcs?.TrySetResult(MessageBoxResult.None); + _ = Tcs?.TrySetResult(MessageBoxResult.None); } protected virtual void CenterWindowOnScreen() { - //TODO MessageBox should be displayed on the window on which the application - double screenWidth = SystemParameters.PrimaryScreenWidth; double screenHeight = SystemParameters.PrimaryScreenHeight; - Left = (screenWidth / 2) - (Width / 2); - Top = (screenHeight / 2) - (Height / 2); + SetCurrentValue(LeftProperty, (screenWidth / 2) - (Width / 2)); + SetCurrentValue(TopProperty, (screenHeight / 2) - (Height / 2)); + } + + private void CenterWindowOnOwner() + { + double left = Owner.Left + ((Owner.Width - Width) / 2); + double top = Owner.Top + ((Owner.Height - Height) / 2); + + SetCurrentValue(LeftProperty, left); + SetCurrentValue(TopProperty, top); } /// /// Occurs after the is clicked /// - /// + /// The MessageBox button protected virtual void OnButtonClick(MessageBoxButton button) { MessageBoxResult result = button switch @@ -405,49 +431,49 @@ protected virtual void OnButtonClick(MessageBoxButton button) _ => MessageBoxResult.None }; - Tcs?.TrySetResult(result); + _ = Tcs?.TrySetResult(result); base.Close(); } private void RemoveTitleBarAndApplyMica() { - UnsafeNativeMethods.RemoveWindowTitlebarContents(this); - WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Mica); + _ = UnsafeNativeMethods.RemoveWindowTitlebarContents(this); + _ = WindowBackdrop.ApplyBackdrop(this, WindowBackdropType.Mica); } - #region Resize private methods - private void ResizeWidth(UIElement element) { if (Width <= MaxWidth) + { return; + } - Width = MaxWidth; + SetCurrentValue(WidthProperty, MaxWidth); element.UpdateLayout(); - Height = element.DesiredSize.Height; + SetCurrentValue(HeightProperty, element.DesiredSize.Height); if (Height > MaxHeight) { - MaxHeight = Height; + SetCurrentValue(MaxHeightProperty, Height); } } private void ResizeHeight(UIElement element) { if (Height <= MaxHeight) + { return; + } - Height = MaxHeight; + SetCurrentValue(HeightProperty, MaxHeight); element.UpdateLayout(); - Width = element.DesiredSize.Width; + SetCurrentValue(WidthProperty, element.DesiredSize.Width); if (Width > MaxWidth) { - MaxWidth = Width; + SetCurrentValue(MaxWidthProperty, Width); } } - - #endregion } diff --git a/source/RevitLookup.UI/Controls/MessageBox/MessageBox.xaml b/source/RevitLookup.UI/Controls/MessageBox/MessageBox.xaml index aaeb848d6..de5f9245a 100644 --- a/source/RevitLookup.UI/Controls/MessageBox/MessageBox.xaml +++ b/source/RevitLookup.UI/Controls/MessageBox/MessageBox.xaml @@ -106,6 +106,7 @@ Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type controls:MessageBox}}, Path=TemplateButtonCommand, Mode=OneTime}" CommandParameter="{x:Static controls:MessageBoxButton.Primary}" Content="{TemplateBinding PrimaryButtonText}" + Icon="{TemplateBinding PrimaryButtonIcon}" IsDefault="True" /> + Content="{TemplateBinding SecondaryButtonText}" + Icon="{TemplateBinding SecondaryButtonIcon}" /> diff --git a/source/RevitLookup.UI/Controls/NavigationView/INavigationView.cs b/source/RevitLookup.UI/Controls/NavigationView/INavigationView.cs index 2ef6e5b2c..3f8e9aa75 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/INavigationView.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/INavigationView.cs @@ -3,11 +3,12 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. +/* Based on Windows UI Library + Copyright(c) Microsoft Corporation.All rights reserved. */ using System.Collections; using System.Windows.Controls; +using Wpf.Ui.Abstractions; using Wpf.Ui.Animations; // ReSharper disable once CheckNamespace @@ -29,14 +30,14 @@ public interface INavigationView Visibility HeaderVisibility { get; set; } /// - /// Gets or sets a value that indicates whether the header is always visible. + /// Gets or sets a value indicating whether the header is always visible. /// bool AlwaysShowHeader { get; set; } /// /// Gets the collection of menu items displayed in the NavigationView. /// - IList MenuItems { get; set; } + IList MenuItems { get; } /// /// Gets or sets an object source used to generate the content of the NavigationView menu. @@ -46,7 +47,7 @@ public interface INavigationView /// /// Gets the list of objects to be used as navigation items in the footer menu. /// - IList FooterMenuItems { get; set; } + IList FooterMenuItems { get; } /// /// Gets or sets the object that represents the navigation items to be used in the footer menu. @@ -64,7 +65,7 @@ public interface INavigationView object? ContentOverlay { get; set; } /// - /// Gets a value that indicates whether the back button is enabled or disabled. + /// Gets a value indicating whether the back button is enabled or disabled. /// bool IsBackEnabled { get; } @@ -75,17 +76,17 @@ public interface INavigationView NavigationViewBackButtonVisible IsBackButtonVisible { get; set; } /// - /// Gets or sets a value that indicates whether the toggle button is visible. + /// Gets or sets a value indicating whether the toggle button is visible. /// bool IsPaneToggleVisible { get; set; } /// - /// Gets or sets a value that specifies whether the NavigationView pane is expanded to its full width. + /// Gets or sets a value indicating whether the NavigationView pane is expanded to its full width. /// bool IsPaneOpen { get; set; } /// - /// Gets or sets a value that determines whether the pane is shown. + /// Gets or sets a value indicating whether the pane is shown. /// bool IsPaneVisible { get; set; } @@ -115,7 +116,7 @@ public interface INavigationView object? PaneFooter { get; set; } /// - /// Gets a value that specifies how the pane and content areas of a NavigationView are being shown. + /// Gets or sets a value that specifies how the pane and content areas of a NavigationView are being shown. /// It is not the same PaneDisplayMode as in WinUi. /// NavigationViewPaneDisplayMode PaneDisplayMode { get; set; } @@ -136,7 +137,7 @@ public interface INavigationView BreadcrumbBar? BreadcrumbBar { get; set; } /// - /// Template Property for and . + /// Gets or sets the template property for and . /// ControlTemplate? ItemTemplate { get; set; } @@ -191,7 +192,7 @@ public interface INavigationView event TypedEventHandler Navigated; /// - /// Gets a value that indicates whether there is at least one entry in back navigation history. + /// Gets a value indicating whether there is at least one entry in back navigation history. /// bool CanGoBack { get; } @@ -210,9 +211,6 @@ public interface INavigationView /// /// Synchronously adds an element to the navigation stack and navigates current navigation Frame to the /// - /// - /// - /// bool NavigateWithHierarchy(Type pageType, object? dataContext = null); /// @@ -245,7 +243,7 @@ public interface INavigationView /// /// Allows you to assign to the NavigationView a special service responsible for retrieving the page instances. /// - void SetPageService(IPageService pageService); + void SetPageProviderService(INavigationViewPageProvider navigationViewPageProvider); /// /// Allows you to assign a general to the NavigationView that will be used to retrieve page instances and view models. diff --git a/source/RevitLookup.UI/Controls/NavigationView/INavigationViewItem.cs b/source/RevitLookup.UI/Controls/NavigationView/INavigationViewItem.cs index cbaa06fe7..1bdddbee3 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/INavigationViewItem.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/INavigationViewItem.cs @@ -3,8 +3,8 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. +/* Based on Windows UI Library + Copyright(c) Microsoft Corporation.All rights reserved. */ using System.Collections; using System.Windows.Controls; @@ -18,12 +18,12 @@ namespace Wpf.Ui.Controls; public interface INavigationViewItem { /// - /// Unique identifier that allows the item to be located in the navigation. + /// Gets the unique identifier that allows the item to be located in the navigation. /// string Id { get; } /// - /// Get or sets content + /// Gets or sets the content /// object Content { get; set; } @@ -35,7 +35,7 @@ public interface INavigationViewItem /// /// Gets the collection of menu items displayed in the NavigationView. /// - IList MenuItems { get; set; } + IList MenuItems { get; } /// /// Gets or sets an object source used to generate the content of the NavigationView menu. @@ -43,40 +43,39 @@ public interface INavigationViewItem object? MenuItemsSource { get; set; } /// - /// Gets information whether the current element is active. + /// Gets a value indicating whether the current element is active. /// bool IsActive { get; } /// - /// Gets information whether the sub- are expanded. + /// Gets or sets a value indicating whether the sub- are expanded. /// bool IsExpanded { get; internal set; } /// - /// A unique tag used by the parent navigation system for the purpose of searching and navigating. + /// Gets or sets the unique tag used by the parent navigation system for the purpose of searching and navigating. /// string TargetPageTag { get; set; } /// - /// The type of the page to be navigated. (Should be derived from ). + /// Gets or sets the type of the page to be navigated. (Should be derived from ). /// Type? TargetPageType { get; set; } - InfoBadge? InfoBadge { get; set; } /// - /// Specifies caching characteristics for a page involved in a navigation. + /// Gets or sets the caching characteristics for a page involved in a navigation. /// NavigationCacheMode NavigationCacheMode { get; set; } /// - /// Template Property + /// Gets or sets the template property /// ControlTemplate? Template { get; set; } /// - /// Gets parent if in collection + /// Gets or sets the parent if it's in collection /// INavigationViewItem? NavigationViewItemParent { get; internal set; } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigatedEventArgs.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigatedEventArgs.cs new file mode 100644 index 000000000..5521c782e --- /dev/null +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigatedEventArgs.cs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +/* Based on Windows UI Library + Copyright(c) Microsoft Corporation.All rights reserved. */ + +// ReSharper disable once CheckNamespace +namespace Wpf.Ui.Controls; + +public class NavigatedEventArgs : RoutedEventArgs +{ + public NavigatedEventArgs(RoutedEvent routedEvent, object source) + : base(routedEvent, source) { } + + public required object Page { get; init; } +} diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewEventArgs.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigatingCancelEventArgs.cs similarity index 76% rename from source/RevitLookup.UI/Controls/NavigationView/NavigationViewEventArgs.cs rename to source/RevitLookup.UI/Controls/NavigationView/NavigatingCancelEventArgs.cs index 206552414..7ec4b4cd3 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewEventArgs.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigatingCancelEventArgs.cs @@ -15,13 +15,6 @@ public NavigatingCancelEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public required object Page { get; init; } - public bool Cancel { get; set; } -} -public class NavigatedEventArgs : RoutedEventArgs -{ - public NavigatedEventArgs(RoutedEvent routedEvent, object source) - : base(routedEvent, source) { } - - public required object Page { get; init; } + public bool Cancel { get; set; } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationCache.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationCache.cs index 529a26d37..98c20c7d5 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationCache.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationCache.cs @@ -11,7 +11,7 @@ namespace Wpf.Ui.Controls; internal class NavigationCache { - private IDictionary _entires = new Dictionary(); + private readonly Dictionary _entires = []; public object? Remember(Type? entryType, NavigationCacheMode cacheMode, Func generate) { @@ -22,33 +22,25 @@ internal class NavigationCache if (cacheMode == NavigationCacheMode.Disabled) { -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine($"Cache for {entryType} is disabled. Generating instance using action..."); -#endif + System.Diagnostics.Debug.WriteLine( + $"Cache for {entryType} is disabled. Generating instance using action..." + ); return generate.Invoke(); } if (!_entires.TryGetValue(entryType, out var value)) { -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine($"{entryType} not found in cache, generating instance using action..."); -#endif + System.Diagnostics.Debug.WriteLine( + $"{entryType} not found in cache, generating instance using action..." + ); value = generate.Invoke(); _entires.Add(entryType, value); } -#if DEBUG System.Diagnostics.Debug.WriteLine($"{entryType} found in cache."); -#endif return value; } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.AttachedProperties.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.AttachedProperties.cs index bb1c06a8a..f6c65eadc 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.AttachedProperties.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.AttachedProperties.cs @@ -6,17 +6,61 @@ // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; +/// +/// Defines attached properties for . +/// public partial class NavigationView { + // ============================================================ + // HeaderContent Attached Property + // ============================================================ + + /// Registers attached property NavigationView.HeaderContent public static readonly DependencyProperty HeaderContentProperty = DependencyProperty.RegisterAttached( "HeaderContent", typeof(object), - typeof(FrameworkElement), + typeof(NavigationView), new FrameworkPropertyMetadata(null) ); + /// Helper for getting from . + /// to read from. + /// HeaderContent property value. + [AttachedPropertyBrowsableForType(typeof(FrameworkElement))] public static object? GetHeaderContent(FrameworkElement target) => target.GetValue(HeaderContentProperty); - public static void SetHeaderContent(FrameworkElement target, object headerContent) => + /// Helper for setting on . + /// to set on. + /// HeaderContent property value. + public static void SetHeaderContent(FrameworkElement target, object? headerContent) => target.SetValue(HeaderContentProperty, headerContent); + + // ============================================================ + // NavigationParent Attached Property + // ============================================================ + + /// Identifies the dependency property. + internal static readonly DependencyProperty NavigationParentProperty = + DependencyProperty.RegisterAttached( + nameof(NavigationParent), + typeof(NavigationView), + typeof(NavigationView), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits) + ); + + /// + /// Gets the parent for its children. + /// + internal NavigationView? NavigationParent + { + get => (NavigationView?)GetValue(NavigationParentProperty); + private set => SetValue(NavigationParentProperty, value); + } + + /// Helper for getting from . + /// to read from. + /// NavigationParent property value. + [AttachedPropertyBrowsableForType(typeof(DependencyObject))] + internal static NavigationView? GetNavigationParent(DependencyObject navigationItem) => + navigationItem.GetValue(NavigationParentProperty) as NavigationView; } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Base.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Base.cs index 6a81a2fbd..3b6939051 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Base.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Base.cs @@ -3,8 +3,7 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. +/* Based on Windows UI Library https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.navigationview?view=winrt-22621 */ using System.Collections; using System.Collections.ObjectModel; @@ -15,17 +14,13 @@ // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; -// https://docs.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.navigationview?view=winrt-22621 - /// /// Represents a container that enables navigation of app content. It has a header, a view for the main content, and a menu pane for navigation commands. /// -//[ToolboxItem(true)] -//[System.Drawing.ToolboxBitmap(typeof(NavigationView), "NavigationView.bmp")] public partial class NavigationView : System.Windows.Controls.Control, INavigationView { /// - /// Static constructor which overrides default property metadata. + /// Initializes static members of the class and overrides default property metadata. /// static NavigationView() { @@ -39,32 +34,62 @@ static NavigationView() ); } + /// + /// Initializes a new instance of the class. + /// public NavigationView() { NavigationParent = this; - //It really should be here - MenuItems = new ObservableCollection(); - FooterMenuItems = new ObservableCollection(); - Loaded += OnLoaded; Unloaded += OnUnloaded; SizeChanged += OnSizeChanged; + + // Initialize MenuItems collection + var menuItems = new ObservableCollection(); + menuItems.CollectionChanged += OnMenuItems_CollectionChanged; + SetValue(MenuItemsPropertyKey, menuItems); + + var footerMenuItems = new ObservableCollection(); + footerMenuItems.CollectionChanged += OnMenuItems_CollectionChanged; + SetValue(FooterMenuItemsPropertyKey, footerMenuItems); } /// public INavigationViewItem? SelectedItem { get; protected set; } - protected Dictionary PageIdOrTargetTagNavigationViewsDictionary = new(); - protected Dictionary PageTypeNavigationViewsDictionary = new(); + protected Dictionary PageIdOrTargetTagNavigationViewsDictionary { get; } = + []; + + protected Dictionary PageTypeNavigationViewsDictionary { get; } = []; + + private readonly ObservableCollection _autoSuggestBoxItems = []; + private readonly ObservableCollection _breadcrumbBarItems = []; + + private static readonly Thickness TitleBarPaneOpenMarginDefault = new(35, 0, 0, 0); + private static readonly Thickness TitleBarPaneCompactMarginDefault = new(35, 0, 0, 0); + private static readonly Thickness AutoSuggestBoxMarginDefault = new(8, 8, 8, 16); + private static readonly Thickness FrameMarginDefault = new(0, 50, 0, 0); - private readonly ObservableCollection _autoSuggestBoxItems = new(); - private readonly ObservableCollection _breadcrumbBarItems = new(); + protected static void UpdateVisualState(NavigationView navigationView) + { + // Skip display modes that don't have multiple states + if ( + navigationView.PaneDisplayMode + is NavigationViewPaneDisplayMode.LeftFluent + or NavigationViewPaneDisplayMode.Top + or NavigationViewPaneDisplayMode.Bottom + ) + { + return; + } - private static readonly Thickness s_titleBarPaneOpenMargin = new(35, 0, 0, 0); - private static readonly Thickness s_titleBarPaneCompactMargin = new(35, 0, 0, 0); - private static readonly Thickness s_autoSuggestBoxMargin = new(8, 8, 8, 16); - private static readonly Thickness s_frameMargin = new(0, 50, 0, 0); + _ = VisualStateManager.GoToState( + navigationView, + navigationView.IsPaneOpen ? "PaneOpen" : "PaneCompact", + true + ); + } /// protected override void OnInitialized(EventArgs e) @@ -85,6 +110,7 @@ protected override void OnInitialized(EventArgs e) private void OnLoaded(object sender, RoutedEventArgs e) { // TODO: Refresh + UpdateVisualState((NavigationView)sender); } /// @@ -110,24 +136,32 @@ protected virtual void OnUnloaded(object sender, RoutedEventArgs e) } if (Header is BreadcrumbBar breadcrumbBar) + { breadcrumbBar.ItemClicked -= BreadcrumbBarOnItemClicked; + } if (ToggleButton is not null) + { ToggleButton.Click -= OnToggleButtonClick; + } if (BackButton is not null) + { BackButton.Click -= OnToggleButtonClick; + } if (AutoSuggestBoxSymbolButton is not null) + { AutoSuggestBoxSymbolButton.Click -= AutoSuggestBoxSymbolButtonOnClick; + } } protected override void OnMouseDown(MouseButtonEventArgs e) { - //Back button + // Back button if (e.ChangedButton is MouseButton.XButton1) { - GoBack(); + _ = GoBack(); e.Handled = true; } @@ -147,7 +181,7 @@ protected virtual void OnSizeChanged(object sender, SizeChangedEventArgs e) /// protected virtual void OnBackButtonClick(object sender, RoutedEventArgs e) { - GoBack(); + _ = GoBack(); } /// @@ -155,7 +189,7 @@ protected virtual void OnBackButtonClick(object sender, RoutedEventArgs e) /// protected virtual void OnToggleButtonClick(object sender, RoutedEventArgs e) { - IsPaneOpen = !IsPaneOpen; + SetCurrentValue(IsPaneOpenProperty, !IsPaneOpen); } /// @@ -163,8 +197,8 @@ protected virtual void OnToggleButtonClick(object sender, RoutedEventArgs e) /// protected virtual void AutoSuggestBoxSymbolButtonOnClick(object sender, RoutedEventArgs e) { - IsPaneOpen = !IsPaneOpen; - AutoSuggestBox?.Focus(); + SetCurrentValue(IsPaneOpenProperty, !IsPaneOpen); + _ = AutoSuggestBox?.Focus(); } /// @@ -175,8 +209,8 @@ protected virtual void OnPaneDisplayModeChanged() switch (PaneDisplayMode) { case NavigationViewPaneDisplayMode.LeftFluent: - IsBackButtonVisible = NavigationViewBackButtonVisible.Collapsed; - IsPaneToggleVisible = false; + SetCurrentValue(IsBackButtonVisibleProperty, NavigationViewBackButtonVisible.Collapsed); + SetCurrentValue(IsPaneToggleVisibleProperty, false); break; } } @@ -198,7 +232,7 @@ internal void OnNavigationViewItemClick(NavigationViewItem navigationViewItem) { OnItemInvoked(); - NavigateInternal(navigationViewItem); + _ = NavigateInternal(navigationViewItem); } protected virtual void BreadcrumbBarOnItemClicked( @@ -207,13 +241,15 @@ BreadcrumbBarItemClickedEventArgs e ) { var item = (NavigationViewBreadcrumbItem)e.Item; - Navigate(item.PageId); + _ = Navigate(item.PageId); } private void UpdateAutoSuggestBoxSuggestions() { if (AutoSuggestBox == null) + { return; + } _autoSuggestBoxItems.Clear(); @@ -229,15 +265,21 @@ AutoSuggestBoxSuggestionChosenEventArgs args ) { if (sender.IsSuggestionListOpen) + { return; + } if (args.SelectedItem is not string selectedSuggestBoxItem) + { return; + } if (NavigateToMenuItemFromAutoSuggestBox(MenuItems, selectedSuggestBoxItem)) + { return; + } - NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, selectedSuggestBoxItem); + _ = NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, selectedSuggestBoxItem); } private void AutoSuggestBoxOnQuerySubmitted( @@ -255,33 +297,36 @@ AutoSuggestBoxQuerySubmittedEventArgs args foreach (string queryToken in querySplit) { if (item.IndexOf(queryToken, StringComparison.CurrentCultureIgnoreCase) < 0) + { isMatch = false; + } } if (isMatch) + { suggestions.Add(item); + } } if (suggestions.Count <= 0) + { return; + } var element = suggestions.First(); if (NavigateToMenuItemFromAutoSuggestBox(MenuItems, element)) + { return; + } - NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, element); + _ = NavigateToMenuItemFromAutoSuggestBox(FooterMenuItems, element); } - protected virtual void AddItemsToDictionaries(IList list) + protected virtual void AddItemsToDictionaries(IEnumerable list) { - for (var i = 0; i < list.Count; i++) + foreach (NavigationViewItem singleNavigationViewItem in list.OfType()) { - var singleMenuItem = list[i]; - - if (singleMenuItem is not INavigationViewItem singleNavigationViewItem) - continue; - if (!PageIdOrTargetTagNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.Id)) { PageIdOrTargetTagNavigationViewsDictionary.Add( @@ -303,7 +348,7 @@ protected virtual void AddItemsToDictionaries(IList list) } if ( - singleNavigationViewItem.TargetPageType is not null + singleNavigationViewItem.TargetPageType != null && !PageTypeNavigationViewsDictionary.ContainsKey(singleNavigationViewItem.TargetPageType) ) { @@ -315,10 +360,10 @@ singleNavigationViewItem.TargetPageType is not null singleNavigationViewItem.IsMenuElement = true; - if (singleNavigationViewItem.MenuItems.Count <= 0) - continue; - - AddItemsToDictionaries(singleNavigationViewItem.MenuItems); + if (singleNavigationViewItem.HasMenuItems) + { + AddItemsToDictionaries(singleNavigationViewItem.MenuItems); + } } } @@ -328,25 +373,22 @@ protected virtual void AddItemsToDictionaries() AddItemsToDictionaries(FooterMenuItems); } - protected virtual void AddItemsToAutoSuggestBoxItems(IList list) + protected virtual void AddItemsToAutoSuggestBoxItems(IEnumerable list) { - for (var i = 0; i < list.Count; i++) + foreach (NavigationViewItem singleNavigationViewItem in list.OfType()) { - var singleMenuItem = list[i]; - - if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) - continue; - if ( singleNavigationViewItem is { Content: string content, TargetPageType: { } } && !string.IsNullOrWhiteSpace(content) ) + { _autoSuggestBoxItems.Add(content); + } - if (singleNavigationViewItem.MenuItems.Count <= 0) - continue; - - AddItemsToAutoSuggestBoxItems(singleNavigationViewItem.MenuItems); + if (singleNavigationViewItem.HasMenuItems) + { + AddItemsToAutoSuggestBoxItems(singleNavigationViewItem.MenuItems); + } } } @@ -356,44 +398,49 @@ protected virtual void AddItemsToAutoSuggestBoxItems() AddItemsToAutoSuggestBoxItems(FooterMenuItems); } - protected virtual bool NavigateToMenuItemFromAutoSuggestBox(IList list, string selectedSuggestBoxItem) + protected virtual bool NavigateToMenuItemFromAutoSuggestBox( + IEnumerable list, + string selectedSuggestBoxItem + ) { - for (var i = 0; i < list.Count; i++) + foreach (NavigationViewItem singleNavigationViewItem in list.OfType()) { - var singleMenuItem = list[i]; - - if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) - continue; - if (singleNavigationViewItem.Content is string content && content == selectedSuggestBoxItem) { - NavigateInternal(singleNavigationViewItem); + _ = NavigateInternal(singleNavigationViewItem); singleNavigationViewItem.BringIntoView(); - singleNavigationViewItem.Focus(); // TODO: Element or content? + _ = singleNavigationViewItem.Focus(); // TODO: Element or content? return true; } - if (singleNavigationViewItem.MenuItems.Count <= 0) - continue; - - NavigateToMenuItemFromAutoSuggestBox(singleNavigationViewItem.MenuItems, selectedSuggestBoxItem); + if ( + NavigateToMenuItemFromAutoSuggestBox( + singleNavigationViewItem.MenuItems, + selectedSuggestBoxItem + ) + ) + { + return true; + } } return false; } - protected virtual void UpdateMenuItemsTemplate(IList list) + protected virtual void UpdateMenuItemsTemplate(IEnumerable list) { - for (var i = 0; i < list.Count; i++) + if (ItemTemplate == null) { - var singleMenuItem = list[i]; - - if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) - continue; + return; + } - if (ItemTemplate is not null && singleNavigationViewItem.Template != ItemTemplate) + foreach (var item in list) + { + if (item is NavigationViewItem singleNavigationViewItem) + { singleNavigationViewItem.Template = ItemTemplate; + } } } @@ -406,12 +453,14 @@ protected virtual void UpdateMenuItemsTemplate() protected virtual void CloseNavigationViewItemMenus() { if (Journal.Count <= 0 || IsPaneOpen) + { return; + } DeactivateMenuItems(MenuItems); DeactivateMenuItems(FooterMenuItems); - var currentItem = PageIdOrTargetTagNavigationViewsDictionary[Journal[^1]]; + INavigationViewItem currentItem = PageIdOrTargetTagNavigationViewsDictionary[Journal[^1]]; if (currentItem.NavigationViewItemParent is null) { currentItem.Activate(this); @@ -422,16 +471,14 @@ protected virtual void CloseNavigationViewItemMenus() currentItem.NavigationViewItemParent?.Activate(this); } - protected void DeactivateMenuItems(IList list) + protected void DeactivateMenuItems(IEnumerable list) { - for (var i = 0; i < list.Count; i++) + foreach (var item in list) { - var singleMenuItem = list[i]; - - if (singleMenuItem is not NavigationViewItem singleNavigationViewItem) - continue; - - singleNavigationViewItem.Deactivate(this); + if (item is NavigationViewItem singleNavigationViewItem) + { + singleNavigationViewItem.Deactivate(this); + } } } @@ -459,7 +506,7 @@ private void NavigationStackOnCollectionChanged(object? sender, NotifyCollection _breadcrumbBarItems.Clear(); break; default: - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(e), e.Action, $"Unsupported action: {e.Action}"); } } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Events.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Events.cs index 5b5b9754d..ef2af06f2 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Events.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Events.cs @@ -6,15 +6,15 @@ // Based on Windows UI Library // Copyright(c) Microsoft Corporation.All rights reserved. - // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; +/// +/// Defines events for . +/// public partial class NavigationView { - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent PaneOpenedEvent = EventManager.RegisterRoutedEvent( nameof(PaneOpened), RoutingStrategy.Bubble, @@ -22,9 +22,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent PaneClosedEvent = EventManager.RegisterRoutedEvent( nameof(PaneClosed), RoutingStrategy.Bubble, @@ -32,9 +30,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent( nameof(SelectionChanged), RoutingStrategy.Bubble, @@ -42,9 +38,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent ItemInvokedEvent = EventManager.RegisterRoutedEvent( nameof(ItemInvoked), RoutingStrategy.Bubble, @@ -52,9 +46,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent BackRequestedEvent = EventManager.RegisterRoutedEvent( nameof(BackRequested), RoutingStrategy.Bubble, @@ -62,9 +54,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent NavigatingEvent = EventManager.RegisterRoutedEvent( nameof(Navigating), RoutingStrategy.Bubble, @@ -72,9 +62,7 @@ public partial class NavigationView typeof(NavigationView) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent NavigatedEvent = EventManager.RegisterRoutedEvent( nameof(Navigated), RoutingStrategy.Bubble, @@ -174,8 +162,6 @@ protected virtual void OnBackRequested() /// /// Raises the navigating requested event. /// - /// - /// protected virtual bool OnNavigating(object sourcePage) { var eventArgs = new NavigatingCancelEventArgs(NavigatingEvent, this) { Page = sourcePage }; @@ -188,7 +174,6 @@ protected virtual bool OnNavigating(object sourcePage) /// /// Raises the navigated requested event. /// - /// protected virtual void OnNavigated(object page) { var eventArgs = new NavigatedEventArgs(NavigatedEvent, this) { Page = page }; diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Navigation.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Navigation.cs index c8a0ffd66..638eb407d 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Navigation.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Navigation.cs @@ -3,30 +3,34 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. +/* Based on Windows UI Library */ using System.Collections.ObjectModel; using System.Diagnostics; +using Wpf.Ui.Abstractions; // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; +/// +/// Defines navigation logic and state management for . +/// public partial class NavigationView { - protected readonly List Journal = new(50); + protected List Journal { get; } = new(50); - protected readonly ObservableCollection NavigationStack = new(); + protected ObservableCollection NavigationStack { get; } = []; private readonly NavigationCache _cache = new(); private readonly Dictionary< INavigationViewItem, List - > _complexNavigationStackHistory = new(); + > _complexNavigationStackHistory = []; private IServiceProvider? _serviceProvider; - private IPageService? _pageService; + + private INavigationViewPageProvider? _pageService; private int _currentIndexInJournal; @@ -34,7 +38,8 @@ private readonly Dictionary< public bool CanGoBack => Journal.Count > 1 && _currentIndexInJournal >= 0; /// - public void SetPageService(IPageService pageService) => _pageService = pageService; + public void SetPageProviderService(INavigationViewPageProvider navigationViewPageProvider) => + _pageService = navigationViewPageProvider; /// public void SetServiceProvider(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; @@ -42,39 +47,49 @@ private readonly Dictionary< /// public virtual bool Navigate(Type pageType, object? dataContext = null) { - if (!PageTypeNavigationViewsDictionary.TryGetValue(pageType, out var navigationViewItem)) + if ( + PageTypeNavigationViewsDictionary.TryGetValue( + pageType, + out INavigationViewItem? navigationViewItem + ) + ) { - return TryToNavigateWithoutINavigationViewItem(pageType, false, dataContext); + return NavigateInternal(navigationViewItem, dataContext); } - return NavigateInternal(navigationViewItem, dataContext); + return TryToNavigateWithoutINavigationViewItem(pageType, false, dataContext); } /// public virtual bool Navigate(string pageIdOrTargetTag, object? dataContext = null) { if ( - !PageIdOrTargetTagNavigationViewsDictionary.TryGetValue( + PageIdOrTargetTagNavigationViewsDictionary.TryGetValue( pageIdOrTargetTag, out INavigationViewItem? navigationViewItem ) ) { - return false; + return NavigateInternal(navigationViewItem, dataContext); } - return NavigateInternal(navigationViewItem, dataContext); + return false; } /// public virtual bool NavigateWithHierarchy(Type pageType, object? dataContext = null) { - if (!PageTypeNavigationViewsDictionary.TryGetValue(pageType, out var navigationViewItem)) + if ( + PageTypeNavigationViewsDictionary.TryGetValue( + pageType, + out INavigationViewItem? navigationViewItem + ) + ) { - return TryToNavigateWithoutINavigationViewItem(pageType, true, dataContext); + return NavigateInternal(navigationViewItem, dataContext, true); } - return NavigateInternal(navigationViewItem, dataContext, true); + return TryToNavigateWithoutINavigationViewItem(pageType, true, dataContext); } /// @@ -115,19 +130,19 @@ public virtual bool GoForward() { throw new NotImplementedException(); - //if (Journal.Count <= 1) - //{ - // return false; - //} + /*if (Journal.Count <= 1) + { + return false; + } - //_currentIndexInJournal += 1; + _currentIndexInJournal += 1; - //if (_currentIndexInJournal > Journal.Count - 1) - //{ - // return false; - //} + if (_currentIndexInJournal > Journal.Count - 1) + { + return false; + } - //return Navigate(Journal[_currentIndexInJournal]); + return Navigate(Journal[_currentIndexInJournal]);*/ } /// @@ -188,27 +203,19 @@ private bool NavigateInternal( if (OnNavigating(pageInstance)) { -#if DEBUG System.Diagnostics.Debug.WriteLineIf(EnableDebugMessages, "Navigation canceled"); -#endif return false; } -#if DEBUG - System - .Diagnostics - .Debug - .WriteLineIf( - EnableDebugMessages, - $"DEBUG | {viewItem.Id} - {(String.IsNullOrEmpty(viewItem.TargetPageTag) ? "NO_TAG" : viewItem.TargetPageTag)} - {viewItem.TargetPageType} | NAVIGATED" - ); -#endif + System.Diagnostics.Debug.WriteLineIf( + EnableDebugMessages, + $"DEBUG | {viewItem.Id} - {(string.IsNullOrEmpty(viewItem.TargetPageTag) ? "NO_TAG" : viewItem.TargetPageTag)} - {viewItem.TargetPageType} | NAVIGATED" + ); OnNavigated(pageInstance); ApplyAttachedProperties(viewItem, pageInstance); - UpdateDictionary(pageInstance); UpdateContent(pageInstance, dataContext); AddToNavigationStack(viewItem, addToNavigationStack, isBackwardsNavigated); @@ -236,45 +243,49 @@ private void AddToJournal(INavigationViewItem viewItem, bool isBackwardsNavigate Journal.Add(viewItem.Id); _currentIndexInJournal++; - IsBackEnabled = CanGoBack; + SetCurrentValue(IsBackEnabledProperty, CanGoBack); -#if DEBUG Debug.WriteLineIf(EnableDebugMessages, $"JOURNAL INDEX {_currentIndexInJournal}"); if (Journal.Count > 0) { Debug.WriteLineIf(EnableDebugMessages, $"JOURNAL LAST ELEMENT {Journal[^1]}"); } -#endif } private object GetNavigationItemInstance(INavigationViewItem viewItem) { if (viewItem.TargetPageType is null) { - throw new ArgumentNullException(nameof(viewItem.TargetPageType)); + throw new InvalidOperationException( + $"The {nameof(viewItem)}.{nameof(viewItem.TargetPageType)} property cannot be null." + ); } if (_serviceProvider is not null) { return _serviceProvider.GetService(viewItem.TargetPageType) - ?? new ArgumentNullException($"{nameof(_serviceProvider.GetService)} returned null"); + ?? throw new InvalidOperationException( + $"{nameof(_serviceProvider)}.{nameof(_serviceProvider.GetService)} returned null for type {viewItem.TargetPageType}." + ); } if (_pageService is not null) { return _pageService.GetPage(viewItem.TargetPageType) - ?? throw new ArgumentNullException($"{nameof(_pageService.GetPage)} returned null"); + ?? throw new InvalidOperationException( + $"{nameof(_pageService)}.{nameof(_pageService.GetPage)} returned null for type {viewItem.TargetPageType}." + ); } return _cache.Remember( - viewItem.TargetPageType, - viewItem.NavigationCacheMode, - ComputeCachedNavigationInstance - ) - ?? throw new ArgumentNullException( - $"Unable to get or create instance of {viewItem.TargetPageType} from cache." - ); + viewItem.TargetPageType, + viewItem.NavigationCacheMode, + ComputeCachedNavigationInstance + ) + ?? throw new InvalidOperationException( + $"Unable to get or create instance of {viewItem.TargetPageType} from cache." + ); object? ComputeCachedNavigationInstance() => GetPageInstanceFromCache(viewItem.TargetPageType); } @@ -288,33 +299,30 @@ private object GetNavigationItemInstance(INavigationViewItem viewItem) if (_serviceProvider is not null) { -#if DEBUG - System - .Diagnostics - .Debug - .WriteLine($"Getting {targetPageType} from cache using IServiceProvider."); -#endif + System.Diagnostics.Debug.WriteLine( + $"Getting {targetPageType} from cache using IServiceProvider." + ); return _serviceProvider.GetService(targetPageType) - ?? new ArgumentNullException($"{nameof(_serviceProvider.GetService)} returned null"); + ?? throw new InvalidOperationException( + $"{nameof(_serviceProvider.GetService)} returned null" + ); } if (_pageService is not null) { -#if DEBUG - System.Diagnostics.Debug.WriteLine($"Getting {targetPageType} from cache using IPageService."); -#endif + System.Diagnostics.Debug.WriteLine( + $"Getting {targetPageType} from cache using INavigationViewPageProvider." + ); return _pageService.GetPage(targetPageType) - ?? throw new ArgumentNullException($"{nameof(_pageService.GetPage)} returned null"); + ?? throw new InvalidOperationException($"{nameof(_pageService.GetPage)} returned null"); } -#if DEBUG System.Diagnostics.Debug.WriteLine($"Getting {targetPageType} from cache using reflection."); -#endif return NavigationViewActivator.CreateInstance(targetPageType) - ?? throw new ArgumentException("Failed to create instance of the page"); + ?? throw new InvalidOperationException("Failed to create instance of the page"); } private static void ApplyAttachedProperties(INavigationViewItem viewItem, object pageInstance) @@ -328,16 +336,6 @@ pageInstance is FrameworkElement frameworkElement } } - private void UpdateDictionary(object? content) - { - if (content is FrameworkElement frameworkViewContent) - { - var window = Window.GetWindow(this); - if (window is null) return; - frameworkViewContent.Resources = window.Resources; - } - } - private void UpdateContent(object? content, object? dataContext = null) { if (dataContext is not null && content is FrameworkElement frameworkViewContent) @@ -345,7 +343,7 @@ private void UpdateContent(object? content, object? dataContext = null) frameworkViewContent.DataContext = dataContext; } - NavigationViewContentPresenter.Navigate(content); + _ = NavigationViewContentPresenter.Navigate(content); } private void OnNavigationViewContentPresenterNavigated( @@ -360,12 +358,10 @@ System.Windows.Navigation.NavigationEventArgs e _ = frame.RemoveBackEntry(); - //var replaced = 1; - //((NavigationViewContentPresenter)sender).JournalOwnership = + /*var replaced = 1; + ((NavigationViewContentPresenter)sender).JournalOwnership =*/ } - #region Navigation stack methods - private void AddToNavigationStack( INavigationViewItem viewItem, bool addToNavigationStack, @@ -418,12 +414,13 @@ private void UpdateCurrentNavigationStackItem(INavigationViewItem viewItem) private void RecreateNavigationStackFromHistory(INavigationViewItem item) { - if (!_complexNavigationStackHistory.TryGetValue(item, out var historyList) || historyList.Count == 0) + List? historyList; + if (!_complexNavigationStackHistory.TryGetValue(item, out historyList) || historyList.Count == 0) { return; } - var latestHistory = historyList[^1]; + INavigationViewItem?[] latestHistory = historyList[^1]; var startIndex = 0; if (latestHistory[0]!.IsMenuElement) @@ -456,7 +453,7 @@ private void RecreateNavigationStackFromHistory(INavigationViewItem item) private void AddToNavigationStackHistory(INavigationViewItem viewItem) { - var lastItem = NavigationStack[^1]; + INavigationViewItem lastItem = NavigationStack[^1]; var startIndex = NavigationStack.IndexOf(viewItem); if (startIndex < 0) @@ -464,7 +461,8 @@ private void AddToNavigationStackHistory(INavigationViewItem viewItem) startIndex = 0; } - if (!_complexNavigationStackHistory.TryGetValue(lastItem, out var historyList)) + List? historyList; + if (!_complexNavigationStackHistory.TryGetValue(lastItem, out historyList)) { historyList = new List(5); _complexNavigationStackHistory.Add(lastItem, historyList); @@ -473,8 +471,7 @@ private void AddToNavigationStackHistory(INavigationViewItem viewItem) int arrayLength = NavigationStack.Count - 1 - startIndex; INavigationViewItem[] array; - //Initializing an array every time well... not an ideal - + // OPTIMIZATION: Initializing an array every time well... not an ideal #if NET6_0_OR_GREATER array = System.Buffers.ArrayPool.Shared.Rent(arrayLength); #else @@ -483,7 +480,7 @@ private void AddToNavigationStackHistory(INavigationViewItem viewItem) historyList.Add(array); - var latestHistory = historyList[^1]; + INavigationViewItem?[] latestHistory = historyList[^1]; int i = 0; for (int j = startIndex; j < NavigationStack.Count - 1; j++) @@ -505,7 +502,7 @@ private void ClearNavigationStack(int navigationStackItemIndex) for (int j = navigationStackCount - 1; j >= navigationStackCount - length; j--) { - NavigationStack.Remove(NavigationStack[j]); + _ = NavigationStack.Remove(NavigationStack[j]); } } @@ -533,6 +530,4 @@ private void ReplaceThirstElementInNavigationStack(INavigationViewItem newItem) NavigationStack[0] = newItem; NavigationStack[0].Activate(this); } - - #endregion -} \ No newline at end of file +} diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Parent.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Parent.cs deleted file mode 100644 index 8daa5a863..000000000 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Parent.cs +++ /dev/null @@ -1,47 +0,0 @@ -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. -// Copyright (C) Leszek Pomianowski and WPF UI Contributors. -// All Rights Reserved. - -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. - -// ReSharper disable once CheckNamespace -namespace Wpf.Ui.Controls; - -public partial class NavigationView -{ - /// - /// Attached property for 's to get its parent. - /// - internal static readonly DependencyProperty NavigationParentProperty = - DependencyProperty.RegisterAttached( - nameof(NavigationParent), - typeof(INavigationView), - typeof(INavigationView), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits) - ); - - /// - /// - /// - internal INavigationView NavigationParent - { - get => (INavigationView)GetValue(NavigationParentProperty); - private set => SetValue(NavigationParentProperty, value); - } - - /// - /// Gets the parent view for its children. - /// - /// - /// Instance of the or . - internal static NavigationView? GetNavigationParent(T navigationItem) - where T : DependencyObject, INavigationViewItem - { - if (navigationItem.GetValue(NavigationParentProperty) is NavigationView navigationView) - return navigationView; - - return null; - } -} diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Properties.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Properties.cs index fd0622596..ea3716c88 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Properties.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.Properties.cs @@ -3,21 +3,21 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. - using System.Collections; +using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Windows.Controls; using Wpf.Ui.Animations; // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; +/// +/// Defines the dependency properties and dp callbacks for control +/// public partial class NavigationView { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty EnableDebugMessagesProperty = DependencyProperty.Register( nameof(EnableDebugMessages), typeof(bool), @@ -25,9 +25,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( nameof(Header), typeof(object), @@ -35,9 +33,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty HeaderVisibilityProperty = DependencyProperty.Register( nameof(HeaderVisibility), typeof(Visibility), @@ -45,9 +41,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(Visibility.Visible) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty AlwaysShowHeaderProperty = DependencyProperty.Register( nameof(AlwaysShowHeader), typeof(bool), @@ -55,49 +49,45 @@ public partial class NavigationView new FrameworkPropertyMetadata(false) ); - /// - /// Property for . - /// - public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register( + private static readonly DependencyPropertyKey MenuItemsPropertyKey = DependencyProperty.RegisterReadOnly( nameof(MenuItems), - typeof(IList), + typeof(ObservableCollection), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnMenuItemsPropertyChanged) + new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. + public static readonly DependencyProperty MenuItemsProperty = MenuItemsPropertyKey.DependencyProperty; + + /// Identifies the dependency property. public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.Register( nameof(MenuItemsSource), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnMenuItemsSourcePropertyChanged) + new FrameworkPropertyMetadata(null, OnMenuItemsSourceChanged) ); - /// - /// Property for . - /// - public static readonly DependencyProperty FooterMenuItemsProperty = DependencyProperty.Register( - nameof(FooterMenuItemsProperty), - typeof(IList), - typeof(NavigationView), - new FrameworkPropertyMetadata(null) - ); + private static readonly DependencyPropertyKey FooterMenuItemsPropertyKey = + DependencyProperty.RegisterReadOnly( + nameof(FooterMenuItems), + typeof(ObservableCollection), + typeof(NavigationView), + new PropertyMetadata(null) + ); - /// - /// Property for . - /// + /// Identifies the dependency property. + public static readonly DependencyProperty FooterMenuItemsProperty = + FooterMenuItemsPropertyKey.DependencyProperty; + + /// Identifies the dependency property. public static readonly DependencyProperty FooterMenuItemsSourceProperty = DependencyProperty.Register( nameof(FooterMenuItemsSource), typeof(object), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnFooterMenuItemsSourcePropertyChanged) + new FrameworkPropertyMetadata(null, OnFooterMenuItemsSourceChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ContentOverlayProperty = DependencyProperty.Register( nameof(ContentOverlay), typeof(object), @@ -105,9 +95,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsBackEnabledProperty = DependencyProperty.Register( nameof(IsBackEnabled), typeof(bool), @@ -115,9 +103,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register( nameof(IsBackButtonVisible), typeof(NavigationViewBackButtonVisible), @@ -125,9 +111,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(NavigationViewBackButtonVisible.Auto) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsPaneToggleVisibleProperty = DependencyProperty.Register( nameof(IsPaneToggleVisible), typeof(bool), @@ -135,19 +119,15 @@ public partial class NavigationView new FrameworkPropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsPaneOpenProperty = DependencyProperty.Register( nameof(IsPaneOpen), typeof(bool), typeof(NavigationView), - new FrameworkPropertyMetadata(false, IsPaneOpenChangedCallback) + new FrameworkPropertyMetadata(true, OnIsPaneOpenChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsPaneVisibleProperty = DependencyProperty.Register( nameof(IsPaneVisible), typeof(bool), @@ -155,9 +135,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty OpenPaneLengthProperty = DependencyProperty.Register( nameof(OpenPaneLength), typeof(double), @@ -165,9 +143,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(0D) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CompactPaneLengthProperty = DependencyProperty.Register( nameof(CompactPaneLength), typeof(double), @@ -175,9 +151,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(0D) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PaneHeaderProperty = DependencyProperty.Register( nameof(PaneHeader), typeof(object), @@ -185,9 +159,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PaneTitleProperty = DependencyProperty.Register( nameof(PaneTitle), typeof(string), @@ -195,9 +167,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PaneFooterProperty = DependencyProperty.Register( nameof(PaneFooter), typeof(object), @@ -205,49 +175,39 @@ public partial class NavigationView new FrameworkPropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty PaneDisplayModeProperty = DependencyProperty.Register( nameof(PaneDisplayMode), typeof(NavigationViewPaneDisplayMode), typeof(NavigationView), - new FrameworkPropertyMetadata(NavigationViewPaneDisplayMode.Left, OnPaneDisplayModePropertyChanged) + new FrameworkPropertyMetadata(NavigationViewPaneDisplayMode.Left, OnPaneDisplayModeChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty AutoSuggestBoxProperty = DependencyProperty.Register( nameof(AutoSuggestBox), typeof(AutoSuggestBox), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnAutoSuggestBoxPropertyChangedCallback) + new FrameworkPropertyMetadata(null, OnAutoSuggestBoxChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TitleBarProperty = DependencyProperty.Register( nameof(TitleBar), typeof(TitleBar), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnTitleBarPropertyChangedCallback) + new FrameworkPropertyMetadata(null, OnTitleBarChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty BreadcrumbBarProperty = DependencyProperty.Register( nameof(BreadcrumbBar), typeof(BreadcrumbBar), typeof(NavigationView), - new FrameworkPropertyMetadata(null, OnBreadcrumbBarPropertyChangedCallback) + new FrameworkPropertyMetadata(null, OnBreadcrumbBarChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register( nameof(ItemTemplate), typeof(ControlTemplate), @@ -255,13 +215,11 @@ public partial class NavigationView new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsMeasure, - OnItemTemplatePropertyChanged + OnItemTemplateChanged ) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TransitionDurationProperty = DependencyProperty.Register( nameof(TransitionDuration), typeof(int), @@ -269,9 +227,7 @@ public partial class NavigationView new FrameworkPropertyMetadata(200) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TransitionProperty = DependencyProperty.Register( nameof(Transition), typeof(Transition), @@ -279,18 +235,16 @@ public partial class NavigationView new FrameworkPropertyMetadata(Transition.FadeInWithSlide) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FrameMarginProperty = DependencyProperty.Register( nameof(FrameMargin), typeof(Thickness), typeof(NavigationView), - new FrameworkPropertyMetadata(new Thickness()) + new FrameworkPropertyMetadata(default(Thickness)) ); /// - /// Enables or disables debugging messages for this control + /// Gets or sets a value indicating whether debugging messages for this control are enabled /// public bool EnableDebugMessages { @@ -320,11 +274,7 @@ public bool AlwaysShowHeader } /// - public IList MenuItems - { - get => (IList)GetValue(MenuItemsProperty); - set => SetValue(MenuItemsProperty, value); - } + public IList MenuItems => (ObservableCollection)GetValue(MenuItemsProperty); /// [Bindable(true)] @@ -345,11 +295,7 @@ public object? MenuItemsSource } /// - public IList FooterMenuItems - { - get => (IList)GetValue(FooterMenuItemsProperty); - set => SetValue(FooterMenuItemsProperty, value); - } + public IList FooterMenuItems => (ObservableCollection)GetValue(FooterMenuItemsProperty); /// [Bindable(true)] @@ -504,57 +450,135 @@ public Thickness FrameMargin set => SetValue(FrameMarginProperty, value); } - private static void OnMenuItemsPropertyChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) + private void OnMenuItemsSource_CollectionChanged( + object? sender, + IList collection, + NotifyCollectionChangedEventArgs e + ) { - if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) + if (ReferenceEquals(sender, collection)) { return; } - if (navigationView.MenuItemsItemsControl is null) + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (var item in e.NewItems) + { + collection.Add(item); + } + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var item in e.OldItems) + { + if (!e.NewItems.Contains(item)) + { + collection.Remove(item); + } + } + break; + + case NotifyCollectionChangedAction.Move: + var moveItem = MenuItems[e.OldStartingIndex]; + collection.RemoveAt(e.OldStartingIndex); + collection.Insert(e.NewStartingIndex, moveItem); + break; + + case NotifyCollectionChangedAction.Replace: + collection.RemoveAt(e.OldStartingIndex); + collection.Insert(e.OldStartingIndex, e.NewItems[0]); + break; + + case NotifyCollectionChangedAction.Reset: + collection.Clear(); + break; + } + } + + private void OnMenuItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (e.NewItems is null) { return; } - if (navigationView.MenuItemsItemsControl.ItemsSource.Equals(enumerableNewValue)) + UpdateMenuItemsTemplate(e.NewItems); + AddItemsToDictionaries(e.NewItems); + } + + private static void OnMenuItemsSourceChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) + { + if (d is not NavigationView navigationView) { return; } - navigationView.MenuItemsItemsControl.ItemsSource = null; - navigationView.MenuItemsItemsControl.ItemsSource = enumerableNewValue; + navigationView.MenuItems.Clear(); + + if (e.NewValue is IEnumerable newItemsSource and not string) + { + foreach (var item in newItemsSource) + { + navigationView.MenuItems.Add(item); + } + } + else if (e.NewValue != null) + { + navigationView.MenuItems.Add(e.NewValue); + } + + if (e.NewValue is INotifyCollectionChanged oc) + { + oc.CollectionChanged += (s, e) => + navigationView.OnMenuItemsSource_CollectionChanged(oc, navigationView.MenuItems, e); + } } - private static void OnMenuItemsSourcePropertyChanged( - DependencyObject? d, - DependencyPropertyChangedEventArgs e - ) + private void OnFooterMenuItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { - if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) + if (e.NewItems is null) { return; } - navigationView.MenuItems = enumerableNewValue; + UpdateMenuItemsTemplate(e.NewItems); + AddItemsToDictionaries(e.NewItems); } - private static void OnFooterMenuItemsSourcePropertyChanged( + private static void OnFooterMenuItemsSourceChanged( DependencyObject? d, DependencyPropertyChangedEventArgs e ) { - if (d is not NavigationView navigationView || e.NewValue is not IList enumerableNewValue) + if (d is not NavigationView navigationView) { return; } - navigationView.FooterMenuItems = enumerableNewValue; + navigationView.FooterMenuItems.Clear(); + + if (e.NewValue is IEnumerable newItemsSource and not string) + { + foreach (var item in newItemsSource) + { + navigationView.FooterMenuItems.Add(item); + } + } + else if (e.NewValue != null) + { + navigationView.FooterMenuItems.Add(e.NewValue); + } + + if (e.NewValue is INotifyCollectionChanged oc) + { + oc.CollectionChanged += (s, e) => + navigationView.OnMenuItemsSource_CollectionChanged(oc, navigationView.FooterMenuItems, e); + } } - private static void OnPaneDisplayModePropertyChanged( - DependencyObject? d, - DependencyPropertyChangedEventArgs e - ) + private static void OnPaneDisplayModeChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -564,10 +588,7 @@ DependencyPropertyChangedEventArgs e navigationView.OnPaneDisplayModeChanged(); } - private static void OnItemTemplatePropertyChanged( - DependencyObject? d, - DependencyPropertyChangedEventArgs e - ) + private static void OnItemTemplateChanged(DependencyObject? d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -577,7 +598,7 @@ DependencyPropertyChangedEventArgs e navigationView.OnItemTemplateChanged(); } - private static void IsPaneOpenChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnIsPaneOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -600,27 +621,15 @@ private static void IsPaneOpenChangedCallback(DependencyObject d, DependencyProp navigationView.CloseNavigationViewItemMenus(); - if (navigationView.TitleBar is not null) - { - navigationView - .TitleBar - .SetCurrentValue( - MarginProperty, - navigationView.IsPaneOpen ? s_titleBarPaneOpenMargin : s_titleBarPaneCompactMargin - ); - } - - _ = VisualStateManager.GoToState( - navigationView, - navigationView.IsPaneOpen ? "PaneOpen" : "PaneCompact", - true + navigationView.TitleBar?.SetCurrentValue( + MarginProperty, + navigationView.IsPaneOpen ? TitleBarPaneOpenMarginDefault : TitleBarPaneCompactMarginDefault ); + + UpdateVisualState(navigationView); } - private static void OnTitleBarPropertyChangedCallback( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) + private static void OnTitleBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -632,7 +641,7 @@ DependencyPropertyChangedEventArgs e navigationView.FrameMargin = new Thickness(0); oldValue.Margin = new Thickness(0); - if (navigationView.AutoSuggestBox?.Margin == s_autoSuggestBoxMargin) + if (navigationView.AutoSuggestBox?.Margin == AutoSuggestBoxMarginDefault) { navigationView.AutoSuggestBox.SetCurrentValue(MarginProperty, new Thickness(0)); } @@ -645,19 +654,16 @@ DependencyPropertyChangedEventArgs e return; } - navigationView.FrameMargin = s_frameMargin; - titleBar.Margin = s_titleBarPaneOpenMargin; + navigationView.FrameMargin = FrameMarginDefault; + titleBar.Margin = TitleBarPaneOpenMarginDefault; if (navigationView.AutoSuggestBox?.Margin is { Bottom: 0, Left: 0, Right: 0, Top: 0 }) { - navigationView.AutoSuggestBox.SetCurrentValue(MarginProperty, s_autoSuggestBoxMargin); + navigationView.AutoSuggestBox.SetCurrentValue(MarginProperty, AutoSuggestBoxMarginDefault); } } - private static void OnAutoSuggestBoxPropertyChangedCallback( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) + private static void OnAutoSuggestBoxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -681,18 +687,15 @@ DependencyPropertyChangedEventArgs e autoSuggestBox.QuerySubmitted += navigationView.AutoSuggestBoxOnQuerySubmitted; if ( - navigationView.TitleBar?.Margin == s_titleBarPaneOpenMargin + navigationView.TitleBar?.Margin == TitleBarPaneOpenMarginDefault && autoSuggestBox.Margin is { Bottom: 0, Left: 0, Right: 0, Top: 0 } ) { - autoSuggestBox.Margin = s_autoSuggestBoxMargin; + autoSuggestBox.Margin = AutoSuggestBoxMarginDefault; } } - private static void OnBreadcrumbBarPropertyChangedCallback( - DependencyObject d, - DependencyPropertyChangedEventArgs e - ) + private static void OnBreadcrumbBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not NavigationView navigationView) { @@ -714,7 +717,7 @@ DependencyPropertyChangedEventArgs e breadcrumbBar.ItemsSource = navigationView._breadcrumbBarItems; breadcrumbBar.ItemTemplate ??= - Application.MainWindow.TryFindResource("NavigationViewItemDataTemplate") as DataTemplate; + UiApplication.Current.TryFindResource("NavigationViewItemDataTemplate") as DataTemplate; breadcrumbBar.ItemClicked += navigationView.BreadcrumbBarOnItemClicked; } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.TemplateParts.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.TemplateParts.cs index d5a99d713..46309752c 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationView.TemplateParts.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationView.TemplateParts.cs @@ -7,8 +7,14 @@ // Copyright(c) Microsoft Corporation.All rights reserved. // ReSharper disable once CheckNamespace + +using Wpf.Ui.Appearance; + namespace Wpf.Ui.Controls; +/// +/// Defines the template parts for the control +/// [TemplatePart( Name = TemplateElementNavigationViewContentPresenter, Type = typeof(NavigationViewContentPresenter) @@ -61,34 +67,34 @@ public partial class NavigationView private const string TemplateElementAutoSuggestBoxSymbolButton = "PART_AutoSuggestBoxSymbolButton"; /// - /// Control responsible for rendering the content. + /// Gets or sets the control responsible for rendering the content. /// - protected NavigationViewContentPresenter NavigationViewContentPresenter = null!; + protected NavigationViewContentPresenter NavigationViewContentPresenter { get; set; } = null!; /// - /// Control located at the top of the pane with left arrow icon. + /// Gets or sets the control located at the top of the pane with left arrow icon. /// - protected System.Windows.Controls.ItemsControl MenuItemsItemsControl = null!; + protected System.Windows.Controls.ItemsControl MenuItemsItemsControl { get; set; } = null!; /// - /// Control located at the top of the pane with hamburger icon. + /// Gets or sets the control located at the top of the pane with hamburger icon. /// - protected System.Windows.Controls.ItemsControl FooterMenuItemsItemsControl = null!; + protected System.Windows.Controls.ItemsControl FooterMenuItemsItemsControl { get; set; } = null!; /// - /// Control located at the top of the pane with left arrow icon. + /// Gets or sets the control located at the top of the pane with left arrow icon. /// - protected System.Windows.Controls.Button? BackButton; + protected System.Windows.Controls.Button? BackButton { get; set; } /// - /// Control located at the top of the pane with hamburger icon. + /// Gets or sets the control located at the top of the pane with hamburger icon. /// - protected System.Windows.Controls.Button? ToggleButton; + protected System.Windows.Controls.Button? ToggleButton { get; set; } /// - /// Control that is visitable if PaneDisplayMode="Left" and in compact state + /// Gets or sets the control that is visitable if PaneDisplayMode="Left" and in compact state /// - protected System.Windows.Controls.Button? AutoSuggestBoxSymbolButton; + protected System.Windows.Controls.Button? AutoSuggestBoxSymbolButton { get; set; } /// public override void OnApplyTemplate() @@ -105,8 +111,14 @@ public override void OnApplyTemplate() TemplateElementFooterMenuItemsItemsControl ); - MenuItemsItemsControl.ItemsSource = MenuItems; - FooterMenuItemsItemsControl.ItemsSource = FooterMenuItems; + MenuItemsItemsControl.SetCurrentValue( + System.Windows.Controls.ItemsControl.ItemsSourceProperty, + MenuItems + ); + FooterMenuItemsItemsControl.SetCurrentValue( + System.Windows.Controls.ItemsControl.ItemsSourceProperty, + FooterMenuItems + ); if (NavigationViewContentPresenter is not null) { @@ -146,7 +158,9 @@ protected T GetTemplateChild(string name) where T : DependencyObject { if (GetTemplateChild(name) is not T dependencyObject) + { throw new ArgumentNullException(name); + } return dependencyObject; } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewActivator.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewActivator.cs index 3ca08e37d..c826358dc 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewActivator.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewActivator.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Windows.Controls; +using Wpf.Ui.Abstractions; using Wpf.Ui.Designer; // ReSharper disable once CheckNamespace @@ -24,11 +25,14 @@ internal static class NavigationViewActivator public static FrameworkElement? CreateInstance(Type pageType, object? dataContext = null) { if (!typeof(FrameworkElement).IsAssignableFrom(pageType)) + { throw new InvalidCastException( $"PageType of the ${typeof(INavigationViewItem)} must be derived from {typeof(FrameworkElement)}. {pageType} is not." ); + } if (DesignerHelper.IsInDesignMode) + { return new Page { Content = new TextBlock @@ -36,13 +40,14 @@ internal static class NavigationViewActivator Text = "Pages are not rendered while using the Designer. Edit the page template directly." } }; + } FrameworkElement? instance; #if NET48_OR_GREATER || NETCOREAPP3_0_OR_GREATER if (ControlsServices.ControlsServiceProvider != null) { - var pageConstructors = pageType.GetConstructors(); + ConstructorInfo[] pageConstructors = pageType.GetConstructors(); var parameterlessCount = pageConstructors.Count(ctor => ctor.GetParameters().Length == 0); var parameterfullCount = pageConstructors.Length - parameterlessCount; @@ -52,15 +57,11 @@ internal static class NavigationViewActivator } else if (parameterlessCount == 0 && parameterfullCount > 0) { - ConstructorInfo? selectedCtor = FitBestConstructor(pageConstructors, dataContext); - - if (selectedCtor == null) - { - throw new InvalidOperationException( - $"The {pageType} page does not have a parameterless constructor or the required services have not been configured for dependency injection. Use the static {nameof(ControlsServices)} class to initialize the GUI library with your service provider. If you are using {typeof(IPageService)} do not navigate initially and don't use Cache or Precache." + ConstructorInfo? selectedCtor = + FitBestConstructor(pageConstructors, dataContext) + ?? throw new InvalidOperationException( + $"The {pageType} page does not have a parameterless constructor or the required services have not been configured for dependency injection. Use the static {nameof(ControlsServices)} class to initialize the GUI library with your service provider. If you are using {typeof(INavigationViewPageProvider)} do not navigate initially and don't use Cache or Precache." ); - } - instance = InvokeElementConstructor(selectedCtor, dataContext); SetDataContext(instance, dataContext); @@ -80,15 +81,11 @@ internal static class NavigationViewActivator } } - ConstructorInfo? emptyConstructor = FindParameterlessConstructor(pageType); - - if (emptyConstructor == null) - { - throw new InvalidOperationException( - $"The {pageType} page does not have a parameterless constructor. If you are using {typeof(IPageService)} do not navigate initially and don't use Cache or Precache." + ConstructorInfo emptyConstructor = + FindParameterlessConstructor(pageType) + ?? throw new InvalidOperationException( + $"The {pageType} page does not have a parameterless constructor. If you are using {typeof(INavigationViewPageProvider)} do not navigate initially and don't use Cache or Precache." ); - } - instance = emptyConstructor.Invoke(null) as FrameworkElement; SetDataContext(instance, dataContext); @@ -107,11 +104,11 @@ internal static class NavigationViewActivator } /// - /// Picks a constructor which has the most satisfiable arguments count. + /// Picks the constructor with the highest number of satisfiable parameters based on the provided context. /// - /// - /// - /// + /// Array of constructors to evaluate. + /// Context used to determine parameter satisfaction. + /// The constructor with the most satisfiable arguments, or null if none are fully satisfiable. private static ConstructorInfo? FitBestConstructor( ConstructorInfo[] parameterfullCtors, object? dataContext @@ -120,26 +117,24 @@ internal static class NavigationViewActivator return parameterfullCtors .Select(ctor => { - var parameters = ctor.GetParameters(); - var argumentResolution = parameters.Select(prm => - { - var resolved = ResolveConstructorParameter(prm.ParameterType, dataContext); - return resolved != null; - }); - var fullyResolved = argumentResolution.All(resolved => resolved == true); - var score = fullyResolved ? parameters.Length : 0; - - return score == 0 ? null : new { Constructor = ctor, Score = score }; + ParameterInfo[] parameters = ctor.GetParameters(); + int score = parameters.Aggregate( + 0, + (acc, prm) => + acc + (ResolveConstructorParameter(prm.ParameterType, dataContext) != null ? 1 : 0) + ); + score = score != parameters.Length ? 0 : score; + return new { Constructor = ctor, Score = score }; }) - .Where(cs => cs != null) - .OrderBy(cs => cs.Score) + .Where(cs => cs.Score != 0) + .OrderByDescending(cs => cs.Score) .FirstOrDefault() ?.Constructor; } private static FrameworkElement? InvokeElementConstructor(ConstructorInfo ctor, object? dataContext) { - var args = ctor.GetParameters() + IEnumerable args = ctor.GetParameters() .Select(prm => ResolveConstructorParameter(prm.ParameterType, dataContext)); return ctor.Invoke(args.ToArray()) as FrameworkElement; @@ -148,14 +143,11 @@ internal static class NavigationViewActivator private static FrameworkElement? InvokeElementConstructor(Type tPage, object? dataContext) { - var ctor = dataContext is null + ConstructorInfo? ctor = dataContext is null ? tPage.GetConstructor(Type.EmptyTypes) - : tPage.GetConstructor(new[] { dataContext!.GetType() }); - - if (ctor != null) - return ctor.Invoke(new[] { dataContext }) as FrameworkElement; + : tPage.GetConstructor(new[] { dataContext.GetType() }); - return null; + return ctor?.Invoke(new[] { dataContext }) as FrameworkElement; } private static ConstructorInfo? FindParameterlessConstructor(Type? tPage) @@ -171,6 +163,8 @@ internal static class NavigationViewActivator private static void SetDataContext(FrameworkElement? element, object? dataContext) { if (element != null && dataContext != null) + { element.DataContext = dataContext; + } } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewBreadcrumbItem.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewBreadcrumbItem.cs index 52da8819b..0c9e87812 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewBreadcrumbItem.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewBreadcrumbItem.cs @@ -9,7 +9,7 @@ // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; -internal class NavigationViewBreadcrumbItem +public class NavigationViewBreadcrumbItem { public NavigationViewBreadcrumbItem(INavigationViewItem item) { @@ -18,5 +18,6 @@ public NavigationViewBreadcrumbItem(INavigationViewItem item) } public object Content { get; } + public string PageId { get; } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewCompact.xaml b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewCompact.xaml index 86cd8effd..f8d2f0759 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewCompact.xaml +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewCompact.xaml @@ -17,6 +17,7 @@ - + diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.cs b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.cs index e2fc899f9..f3b852f35 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.cs +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.cs @@ -3,22 +3,21 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. +/* Based on Windows UI Library */ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Navigation; +using Wpf.Ui.Abstractions.Controls; using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; public class NavigationViewContentPresenter : Frame { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TransitionDurationProperty = DependencyProperty.Register( nameof(TransitionDuration), typeof(int), @@ -26,9 +25,7 @@ public class NavigationViewContentPresenter : Frame new FrameworkPropertyMetadata(200) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TransitionProperty = DependencyProperty.Register( nameof(Transition), typeof(Transition), @@ -36,9 +33,7 @@ public class NavigationViewContentPresenter : Frame new FrameworkPropertyMetadata(Transition.FadeInWithSlide) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsDynamicScrollViewerEnabledProperty = DependencyProperty.Register( nameof(IsDynamicScrollViewerEnabled), @@ -47,7 +42,8 @@ public class NavigationViewContentPresenter : Frame new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure) ); - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public int TransitionDuration { get => (int)GetValue(TransitionDurationProperty); @@ -64,7 +60,7 @@ public Transition Transition } /// - /// Gets a value indicating whether the dynamic scroll viewer is enabled. + /// Gets or sets a value indicating whether the dynamic scroll viewer is enabled. /// public bool IsDynamicScrollViewerEnabled { @@ -78,25 +74,26 @@ static NavigationViewContentPresenter() typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(typeof(NavigationViewContentPresenter)) ); - + NavigationUIVisibilityProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(NavigationUIVisibility.Hidden) ); - + SandboxExternalContentProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(true) ); - + JournalOwnershipProperty.OverrideMetadata( typeof(NavigationViewContentPresenter), new FrameworkPropertyMetadata(JournalOwnership.UsesParentJournal) ); - // - // ScrollViewer - // .CanContentScrollProperty - // .OverrideMetadata(typeof(Page), new FrameworkPropertyMetadata(true)); + + ScrollViewer.CanContentScrollProperty.OverrideMetadata( + typeof(Page), + new FrameworkPropertyMetadata(true) + ); } public NavigationViewContentPresenter() @@ -129,7 +126,7 @@ protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); - //I didn't understand something, but why is it necessary? + // REVIEW: I didn't understand something, but why is it necessary? Unloaded += static (sender, _) => { if (sender is NavigationViewContentPresenter navigator) @@ -144,11 +141,23 @@ protected override void OnMouseDown(MouseButtonEventArgs e) if (e.ChangedButton is MouseButton.XButton1 or MouseButton.XButton2) { e.Handled = true; + return; } base.OnMouseDown(e); } + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if (e.Key == Key.F5) + { + e.Handled = true; + return; + } + + base.OnPreviewKeyDown(e); + } + protected virtual void OnNavigating(System.Windows.Navigation.NavigatingCancelEventArgs eventArgs) { NotifyContentAboutNavigatingTo(eventArgs.Content); @@ -170,7 +179,10 @@ protected virtual void OnNavigated(NavigationEventArgs eventArgs) return; } - IsDynamicScrollViewerEnabled = ScrollViewer.GetCanContentScroll(dependencyObject); + SetCurrentValue( + IsDynamicScrollViewerEnabledProperty, + ScrollViewer.GetCanContentScroll(dependencyObject) + ); } private void ApplyTransitionEffectToNavigatedPage(object content) @@ -180,50 +192,40 @@ private void ApplyTransitionEffectToNavigatedPage(object content) return; } - TransitionAnimationProvider.ApplyTransition(content, Transition, TransitionDuration); + _ = TransitionAnimationProvider.ApplyTransition(content, Transition, TransitionDuration); } private static void NotifyContentAboutNavigatingTo(object content) { - if (content is INavigationAware navigationAwareNavigationContent) - { - navigationAwareNavigationContent.OnNavigatedTo(); - } - - if ( - content is INavigableView - { - ViewModel: INavigationAware navigationAwareNavigableViewViewModel - } - ) - { - navigationAwareNavigableViewViewModel.OnNavigatedTo(); - } - - if (content is FrameworkElement { DataContext: INavigationAware navigationAwareCurrentContent }) - { - navigationAwareCurrentContent.OnNavigatedTo(); - } + NotifyContentAboutNavigating(content, navigationAware => navigationAware.OnNavigatedToAsync()); } private static void NotifyContentAboutNavigatingFrom(object content) { - if (content is INavigationAware navigationAwareNavigationContent) - navigationAwareNavigationContent.OnNavigatedFrom(); + NotifyContentAboutNavigating(content, navigationAware => navigationAware.OnNavigatedFromAsync()); + } - if ( - content is INavigableView - { - ViewModel: INavigationAware navigationAwareNavigableViewViewModel - } - ) + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "ReSharper", + "SuspiciousTypeConversion.Global", + Justification = "The library user might make a class inherit from both FrameworkElement and INavigationAware at the same time." + )] + private static void NotifyContentAboutNavigating(object content, Func function) + { + // The order in which the OnNavigatedToAsync/OnNavigatedFromAsync methods of View and ViewModel are called + // is not guaranteed + if (content is INavigationAware navigationAwareContent) { - navigationAwareNavigableViewViewModel.OnNavigatedFrom(); + function(navigationAwareContent); } - if (content is FrameworkElement { DataContext: INavigationAware navigationAwareCurrentContent }) + if (content is INavigableView {ViewModel: INavigationAware navigationAwareViewModel}) + { + function(navigationAwareViewModel); + } + else if (content is FrameworkElement {DataContext: INavigationAware viewModel} && !ReferenceEquals(viewModel, content)) { - navigationAwareCurrentContent.OnNavigatedFrom(); + function(viewModel); } } } diff --git a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.xaml b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.xaml index 46a6cc73e..712e36e6c 100644 --- a/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.xaml +++ b/source/RevitLookup.UI/Controls/NavigationView/NavigationViewContentPresenter.xaml @@ -32,16 +32,15 @@ - - - - - - - - - + + + + + + + + + + + + /// Rotating loading ring. /// -//[ToolboxItem(true)] -//[ToolboxBitmap(typeof(ProgressRing), "ProgressRing.bmp")] public class ProgressRing : System.Windows.Controls.Control { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register( nameof(Progress), typeof(double), typeof(ProgressRing), - new PropertyMetadata(50d, PropertyChangedCallback) + new PropertyMetadata(50d, OnProgressChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsIndeterminateProperty = DependencyProperty.Register( nameof(IsIndeterminate), typeof(bool), @@ -38,9 +32,7 @@ public class ProgressRing : System.Windows.Controls.Control new PropertyMetadata(false) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty EngAngleProperty = DependencyProperty.Register( nameof(EngAngle), typeof(double), @@ -48,9 +40,7 @@ public class ProgressRing : System.Windows.Controls.Control new PropertyMetadata(180.0d) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IndeterminateAngleProperty = DependencyProperty.Register( nameof(IndeterminateAngle), typeof(double), @@ -58,9 +48,7 @@ public class ProgressRing : System.Windows.Controls.Control new PropertyMetadata(180.0d) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CoverRingStrokeProperty = DependencyProperty.RegisterAttached( nameof(CoverRingStroke), typeof(Brush), @@ -73,9 +61,7 @@ public class ProgressRing : System.Windows.Controls.Control ) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty CoverRingVisibilityProperty = DependencyProperty.Register( nameof(CoverRingVisibility), typeof(System.Windows.Visibility), @@ -93,8 +79,8 @@ public double Progress } /// - /// Determines if shows actual values () - /// or generic, continuous progress feedback (). + /// Gets or sets a value indicating whether shows actual values () + /// or generic, continuous progress feedback. /// public bool IsIndeterminate { @@ -121,7 +107,7 @@ public double IndeterminateAngle } /// - /// Background ring fill. + /// Gets background ring fill. /// public Brush CoverRingStroke { @@ -130,7 +116,7 @@ public Brush CoverRingStroke } /// - /// Background ring visibility. + /// Gets background ring visibility. /// public System.Windows.Visibility CoverRingVisibility { @@ -146,27 +132,35 @@ protected void UpdateProgressAngle() var percentage = Progress; if (percentage > 100) + { percentage = 100; + } if (percentage < 0) + { percentage = 0; + } // (360 / 100) * percentage var endAngle = 3.6d * percentage; if (endAngle >= 360) + { endAngle = 359; + } - EngAngle = endAngle; + SetCurrentValue(EngAngleProperty, endAngle); } /// /// Validates the entered and redraws the . /// - protected static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + protected static void OnProgressChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not ProgressRing control) + { return; + } control.UpdateProgressAngle(); } diff --git a/source/RevitLookup.UI/Controls/RadioButton/RadioButton.xaml b/source/RevitLookup.UI/Controls/RadioButton/RadioButton.xaml index 5dec5478b..ffef00b49 100644 --- a/source/RevitLookup.UI/Controls/RadioButton/RadioButton.xaml +++ b/source/RevitLookup.UI/Controls/RadioButton/RadioButton.xaml @@ -62,7 +62,7 @@ Stroke="{DynamicResource RadioButtonOuterEllipseStroke}" StrokeThickness="{StaticResource RadioButtonStrokeThickness}" UseLayoutRounding="False" /> - + - + /// Displays the rating scale with interactions. /// -//[ToolboxItem(true)] -//[ToolboxBitmap(typeof(RatingControl), "RatingControl.bmp")] [TemplatePart(Name = "PART_Star1", Type = typeof(SymbolIcon))] [TemplatePart(Name = "PART_Star2", Type = typeof(SymbolIcon))] [TemplatePart(Name = "PART_Star3", Type = typeof(SymbolIcon))] @@ -28,34 +26,25 @@ private enum StarValue } private const double MaxValue = 5.0D; - private const double MinValue = 0.0D; - private const int OffsetTolerance = 8; - private static readonly SymbolRegular StarSymbol = SymbolRegular.Star28; - private static readonly SymbolRegular StarHalfSymbol = SymbolRegular.StarHalf28; + private SymbolIcon? _symbolIconStarOne; + private SymbolIcon? _symbolIconStarTwo; + private SymbolIcon? _symbolIconStarThree; + private SymbolIcon? _symbolIconStarFour; + private SymbolIcon? _symbolIconStarFive; - private SymbolIcon? _symbolIconStarOne, - _symbolIconStarTwo, - _symbolIconStarThree, - _symbolIconStarFour, - _symbolIconStarFive; - - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( nameof(Value), typeof(double), typeof(RatingControl), - new PropertyMetadata(0.0D, OnValuePropertyChanged) + new PropertyMetadata(0.0D, OnValueChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty MaxRatingProperty = DependencyProperty.Register( nameof(MaxRating), typeof(int), @@ -63,9 +52,7 @@ private enum StarValue new PropertyMetadata(5) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty HalfStarEnabledProperty = DependencyProperty.Register( nameof(HalfStarEnabled), typeof(bool), @@ -73,9 +60,7 @@ private enum StarValue new PropertyMetadata(true) ); - /// - /// Routed event for . - /// + /// Identifies the routed event. public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( nameof(ValueChanged), RoutingStrategy.Bubble, @@ -102,7 +87,7 @@ public int MaxRating } /// - /// Gets or sets the value deciding whether half of the star can be selected. + /// Gets or sets a value indicating whether half of the star can be selected. /// public bool HalfStarEnabled { @@ -126,20 +111,22 @@ protected virtual void OnValueChanged(double oldValue) { if (Value > MaxValue) { - Value = MaxValue; + SetCurrentValue(ValueProperty, MaxValue); return; } if (Value < MinValue) { - Value = MinValue; + SetCurrentValue(ValueProperty, MinValue); return; } if (!Value.Equals(oldValue)) + { RaiseEvent(new RoutedEventArgs(ValueChangedEvent)); + } UpdateStarsFromValue(); } @@ -161,11 +148,13 @@ protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); - var currentPossition = e.GetPosition(this); + Point currentPossition = e.GetPosition(this); var mouseOffset = currentPossition.X * 100 / ActualWidth; if (e.LeftButton != MouseButtonState.Pressed) + { UpdateStarsOnMousePreview(mouseOffset); + } } /// @@ -175,26 +164,32 @@ protected override void OnMouseDown(MouseButtonEventArgs e) { base.OnMouseDown(e); - var currentPossition = e.GetPosition(this); + Point currentPossition = e.GetPosition(this); var mouseOffset = currentPossition.X * 100 / ActualWidth; if (e.LeftButton == MouseButtonState.Pressed) + { UpdateStarsOnMouseClick(mouseOffset); + } } /// - /// Is called after lifting a keyboard key. + /// Adjusts the control's in response to keyboard input, incrementing or decrementing based on the key pressed. /// - /// + /// Key event arguments containing details about the key press. protected override void OnKeyUp(KeyEventArgs e) { base.OnKeyUp(e); if ((e.Key == Key.Right || e.Key == Key.Up) && Value < MaxValue) + { Value += HalfStarEnabled ? 0.5D : 1; + } if ((e.Key == Key.Left || e.Key == Key.Down) && Value > MinValue) + { Value -= HalfStarEnabled ? 0.5D : 1; + } } /// @@ -205,19 +200,29 @@ public override void OnApplyTemplate() base.OnApplyTemplate(); if (GetTemplateChild("PART_Star1") is SymbolIcon starOne) + { _symbolIconStarOne = starOne; + } if (GetTemplateChild("PART_Star2") is SymbolIcon starTwo) + { _symbolIconStarTwo = starTwo; + } if (GetTemplateChild("PART_Star3") is SymbolIcon starThree) + { _symbolIconStarThree = starThree; + } if (GetTemplateChild("PART_Star4") is SymbolIcon starFour) + { _symbolIconStarFour = starFour; + } if (GetTemplateChild("PART_Star5") is SymbolIcon starFive) + { _symbolIconStarFive = starFive; + } UpdateStarsFromValue(); } @@ -231,7 +236,7 @@ private void UpdateStarsOnMouseClick(double offsetPercentage) { var currentValue = ExtractValueFromOffset(offsetPercentage); - Value = currentValue / 2D; + SetCurrentValue(ValueProperty, currentValue / 2.0); } private void UpdateStarsFromValue() @@ -335,7 +340,7 @@ private void SetStarsPresence(int index) private void UpdateStar(int starIndex, StarValue starValue) { - var _selectedIcon = starIndex switch + SymbolIcon? selectedIcon = starIndex switch { 1 => _symbolIconStarTwo, 2 => _symbolIconStarThree, @@ -344,24 +349,26 @@ private void UpdateStar(int starIndex, StarValue starValue) _ => _symbolIconStarOne, }; - if (_selectedIcon is null) + if (selectedIcon is null) + { return; + } switch (starValue) { case StarValue.HalfFilled: - _selectedIcon.Filled = false; - _selectedIcon.Symbol = StarHalfSymbol; + selectedIcon.Filled = false; + selectedIcon.Symbol = StarHalfSymbol; break; case StarValue.Filled: - _selectedIcon.Filled = true; - _selectedIcon.Symbol = StarSymbol; + selectedIcon.Filled = true; + selectedIcon.Symbol = StarSymbol; break; default: - _selectedIcon.Filled = false; - _selectedIcon.Symbol = StarSymbol; + selectedIcon.Filled = false; + selectedIcon.Symbol = StarSymbol; break; } } @@ -373,19 +380,25 @@ private int ExtractValueFromOffset(double offset) if (!HalfStarEnabled) { if (starValue < 2) + { return 0; + } if (starValue % 2 != 0) + { starValue += 1; + } } return starValue; } - private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not RatingControl ratingControl) + { return; + } ratingControl.OnValueChanged((double)e.OldValue); } diff --git a/source/RevitLookup.UI/Controls/RichTextBox/RichTextBox.cs b/source/RevitLookup.UI/Controls/RichTextBox/RichTextBox.cs index 28918e35f..9a68889ef 100644 --- a/source/RevitLookup.UI/Controls/RichTextBox/RichTextBox.cs +++ b/source/RevitLookup.UI/Controls/RichTextBox/RichTextBox.cs @@ -7,13 +7,11 @@ namespace Wpf.Ui.Controls; /// -/// TODO +/// Extends the control with additional properties. /// public class RichTextBox : System.Windows.Controls.RichTextBox { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsTextSelectionEnabledProperty = DependencyProperty.Register( nameof(IsTextSelectionEnabled), typeof(bool), @@ -22,7 +20,7 @@ public class RichTextBox : System.Windows.Controls.RichTextBox ); /// - /// TODO + /// Gets or sets a value indicating whether the user can select text in the control. /// public bool IsTextSelectionEnabled { diff --git a/source/RevitLookup.UI/Controls/ScrollDirection.cs b/source/RevitLookup.UI/Controls/ScrollDirection.cs index d8dcacb34..c9008cbe9 100644 --- a/source/RevitLookup.UI/Controls/ScrollDirection.cs +++ b/source/RevitLookup.UI/Controls/ScrollDirection.cs @@ -3,10 +3,11 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. -// https://github.com/sbaeumlisberger/VirtualizingWrapPanel -// Copyright (C) S. Bäumlisberger -// All Rights Reserved. +/* Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. + https://github.com/sbaeumlisberger/VirtualizingWrapPanel + + Copyright (C) S. Bäumlisberger + All Rights Reserved. */ namespace Wpf.Ui.Controls; diff --git a/source/RevitLookup.UI/Controls/ScrollViewer/ScrollViewer.xaml b/source/RevitLookup.UI/Controls/ScrollViewer/ScrollViewer.xaml index 998b62991..8fad518c3 100644 --- a/source/RevitLookup.UI/Controls/ScrollViewer/ScrollViewer.xaml +++ b/source/RevitLookup.UI/Controls/ScrollViewer/ScrollViewer.xaml @@ -1,4 +1,4 @@ - - - /// Snackbar inform user of a process that an app has performed or will perform. It appears temporarily, towards the bottom of the window. /// public class Snackbar : ContentControl, IAppearanceControl, IIconControl { - #region Static properties - - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsCloseButtonEnabledProperty = DependencyProperty.Register( nameof(IsCloseButtonEnabled), typeof(bool), @@ -29,29 +24,23 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(true) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty SlideTransformProperty = DependencyProperty.Register( nameof(SlideTransform), typeof(TranslateTransform), typeof(Snackbar), - new PropertyMetadata(new TranslateTransform()) + new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsShownProperty = DependencyProperty.Register( nameof(IsShown), typeof(bool), typeof(Snackbar), - new PropertyMetadata(false) + new PropertyMetadata(false, (d, e) => (d as Snackbar)?.OnIsShownChanged(e)) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TimeoutProperty = DependencyProperty.Register( nameof(Timeout), typeof(TimeSpan), @@ -59,9 +48,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(TimeSpan.FromSeconds(2)) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( nameof(Title), typeof(object), @@ -69,9 +56,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register( nameof(TitleTemplate), typeof(DataTemplate), @@ -79,19 +64,15 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IconProperty = DependencyProperty.Register( nameof(Icon), typeof(IconElement), typeof(Snackbar), - new PropertyMetadata(null, null, IconSourceElementConverter.ConvertToIconElement) + new PropertyMetadata(null, null, IconElement.Coerce) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty AppearanceProperty = DependencyProperty.Register( nameof(Appearance), typeof(ControlAppearance), @@ -99,9 +80,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(ControlAppearance.Secondary) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register( nameof(TemplateButtonCommand), typeof(IRelayCommand), @@ -109,9 +88,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl new PropertyMetadata(null) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty ContentForegroundProperty = DependencyProperty.Register( nameof(ContentForeground), typeof(Brush), @@ -122,9 +99,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl ) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent( nameof(Opened), RoutingStrategy.Bubble, @@ -132,9 +107,7 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl typeof(Snackbar) ); - /// - /// Property for . - /// + /// Identifies the routed event. public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent( nameof(Closed), RoutingStrategy.Bubble, @@ -142,10 +115,6 @@ public class Snackbar : ContentControl, IAppearanceControl, IIconControl typeof(Snackbar) ); - #endregion - - #region Properties - /// /// Gets or sets a value indicating whether the close button should be visible. /// @@ -158,26 +127,32 @@ public bool IsCloseButtonEnabled /// /// Gets or sets the transform. /// - public TranslateTransform SlideTransform + public TranslateTransform? SlideTransform { - get => (TranslateTransform)GetValue(SlideTransformProperty); + get => (TranslateTransform?)GetValue(SlideTransformProperty); set => SetValue(SlideTransformProperty, value); } /// - /// Gets the information whether the is visible. + /// Gets or sets a value indicating whether the is visible. /// public bool IsShown { get => (bool)GetValue(IsShownProperty); - set - { - SetValue(IsShownProperty, value); + set => SetValue(IsShownProperty, value); + } - if (value) - OnOpened(); - else - OnClosed(); + protected void OnIsShownChanged(DependencyPropertyChangedEventArgs e) + { + bool newValue = (bool)e.NewValue; + + if (newValue) + { + OnOpened(); + } + else + { + OnClosed(); } } @@ -193,7 +168,7 @@ public TimeSpan Timeout /// /// Gets or sets the title of the . /// - public object Title + public object? Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); @@ -202,24 +177,26 @@ public object Title /// /// Gets or sets the title template of the . /// - public DataTemplate TitleTemplate + public DataTemplate? TitleTemplate { - get => (DataTemplate)GetValue(TitleTemplateProperty); + get => (DataTemplate?)GetValue(TitleTemplateProperty); set => SetValue(TitleTemplateProperty, value); } /// - /// TODO + /// Gets or sets the icon /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public IconElement? Icon { - get => (IconElement)GetValue(IconProperty); + get => (IconElement?)GetValue(IconProperty); set => SetValue(IconProperty, value); } /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public ControlAppearance Appearance { get => (ControlAppearance)GetValue(AppearanceProperty); @@ -227,9 +204,10 @@ public ControlAppearance Appearance } /// - /// Foreground of the . + /// Gets or sets the foreground of the . /// - [Bindable(true), Category("Appearance")] + [Bindable(true)] + [Category("Appearance")] public Brush ContentForeground { get => (Brush)GetValue(ContentForegroundProperty); @@ -237,7 +215,7 @@ public Brush ContentForeground } /// - /// Command triggered after clicking the button in the template. + /// Gets the command triggered after clicking the button in the template. /// public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty); @@ -259,12 +237,10 @@ public event TypedEventHandler Closed remove => RemoveHandler(ClosedEvent, value); } - #endregion - /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class with a specified presenter. /// - /// + /// The to manage the snackbar's display and interactions. public Snackbar(SnackbarPresenter presenter) { Presenter = presenter; @@ -272,7 +248,7 @@ public Snackbar(SnackbarPresenter presenter) SetValue(TemplateButtonCommandProperty, new RelayCommand(_ => Hide())); } - protected readonly SnackbarPresenter Presenter; + protected SnackbarPresenter Presenter { get; } /// /// Shows the @@ -289,9 +265,7 @@ public virtual void Show(bool immediately) { if (immediately) { -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed _ = Presenter.ImmediatelyDisplay(this); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed } else { diff --git a/source/RevitLookup.UI/Controls/Snackbar/Snackbar.xaml b/source/RevitLookup.UI/Controls/Snackbar/Snackbar.xaml index 66608288c..9139cff66 100644 --- a/source/RevitLookup.UI/Controls/Snackbar/Snackbar.xaml +++ b/source/RevitLookup.UI/Controls/Snackbar/Snackbar.xaml @@ -77,28 +77,28 @@ Margin="0" Content="{TemplateBinding Title}" ContentTemplate="{TemplateBinding TitleTemplate}" - TextElement.FontWeight="SemiBold" TextElement.Foreground="{TemplateBinding Foreground}"> diff --git a/source/RevitLookup.UI/Controls/Snackbar/SnackbarPresenter.cs b/source/RevitLookup.UI/Controls/Snackbar/SnackbarPresenter.cs index 05a63222a..aba5a764e 100644 --- a/source/RevitLookup.UI/Controls/Snackbar/SnackbarPresenter.cs +++ b/source/RevitLookup.UI/Controls/Snackbar/SnackbarPresenter.cs @@ -8,9 +8,14 @@ namespace Wpf.Ui.Controls; public class SnackbarPresenter : System.Windows.Controls.ContentPresenter { + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "WpfAnalyzers.DependencyProperty", + "WPF0012:CLR property type should match registered type", + Justification = "seems harmless" + )] public new Snackbar? Content { - get => (Snackbar)GetValue(ContentProperty); + get => (Snackbar?)GetValue(ContentProperty); protected set => SetValue(ContentProperty, value); } @@ -23,14 +28,41 @@ public SnackbarPresenter() }; } - protected readonly Queue Queue = new(); + protected Queue Queue { get; } = new(); - protected CancellationTokenSource CancellationTokenSource = new(); + protected CancellationTokenSource CancellationTokenSource { get; set; } = new(); protected virtual void OnUnloaded() { + if (CancellationTokenSource.IsCancellationRequested) + { + return; + } + + ImmediatelyHideCurrent(); + ResetCancellationTokenSource(); + } + + private void ImmediatelyHideCurrent() + { + if (Content is null) + { + return; + } + CancellationTokenSource.Cancel(); - CancellationTokenSource.Dispose(); + ImmediatelyHidSnackbar(Content); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "WpfAnalyzers.DependencyProperty", + "WPF0041:Set mutable dependency properties using SetCurrentValue", + Justification = "SetCurrentValue(ContentProperty, ...) will not work" + )] + private void ImmediatelyHidSnackbar(Snackbar snackbar) + { + snackbar.SetCurrentValue(Snackbar.IsShownProperty, false); + Content = null; } protected void ResetCancellationTokenSource() @@ -79,11 +111,16 @@ private async Task ShowQueuedSnackbars() } } + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "WpfAnalyzers.DependencyProperty", + "WPF0041:Set mutable dependency properties using SetCurrentValue", + Justification = "SetCurrentValue(ContentProperty, ...) will not work" + )] private async Task ShowSnackbar(Snackbar snackbar) { Content = snackbar; - snackbar.IsShown = true; + snackbar.SetCurrentValue(Snackbar.IsShownProperty, true); try { @@ -97,12 +134,27 @@ private async Task ShowSnackbar(Snackbar snackbar) await HidSnackbar(snackbar); } + [System.Diagnostics.CodeAnalysis.SuppressMessage( + "WpfAnalyzers.DependencyProperty", + "WPF0041:Set mutable dependency properties using SetCurrentValue", + Justification = "SetCurrentValue(ContentProperty, ...) will not work" + )] private async Task HidSnackbar(Snackbar snackbar) { - snackbar.IsShown = false; + snackbar.SetCurrentValue(Snackbar.IsShownProperty, false); await Task.Delay(300); Content = null; } + + ~SnackbarPresenter() + { + if (!CancellationTokenSource.IsCancellationRequested) + { + CancellationTokenSource.Cancel(); + } + + CancellationTokenSource.Dispose(); + } } diff --git a/source/RevitLookup.UI/Controls/SpacingMode.cs b/source/RevitLookup.UI/Controls/SpacingMode.cs index 73a7f8af2..154af3605 100644 --- a/source/RevitLookup.UI/Controls/SpacingMode.cs +++ b/source/RevitLookup.UI/Controls/SpacingMode.cs @@ -3,10 +3,10 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. -// https://github.com/sbaeumlisberger/VirtualizingWrapPanel -// Copyright (C) S. Bäumlisberger -// All Rights Reserved. +/* Based on VirtualizingWrapPanel created by S. Bäumlisberger licensed under MIT license. + https://github.com/sbaeumlisberger/VirtualizingWrapPanel + Copyright (C) S. Bäumlisberger + All Rights Reserved. */ namespace Wpf.Ui.Controls; diff --git a/source/RevitLookup.UI/Controls/SplitButton/SplitButton.cs b/source/RevitLookup.UI/Controls/SplitButton/SplitButton.cs index c168fd27f..8d2e4aac4 100644 --- a/source/RevitLookup.UI/Controls/SplitButton/SplitButton.cs +++ b/source/RevitLookup.UI/Controls/SplitButton/SplitButton.cs @@ -15,31 +15,27 @@ namespace Wpf.Ui.Controls; [TemplatePart(Name = TemplateElementToggleButton, Type = typeof(ToggleButton))] public class SplitButton : Wpf.Ui.Controls.Button { - private ContextMenu? _contextMenu; - /// /// Template element represented by the ToggleButton name. /// - private const string TemplateElementToggleButton = "ToggleButton"; + private const string TemplateElementToggleButton = "PART_ToggleButton"; - /// - /// Control responsible for toggling the drop-down button. - /// - protected ToggleButton SplitButtonToggleButton = null!; + private ContextMenu? _contextMenu; /// - /// Property for . + /// Gets or sets control responsible for toggling the drop-down button. /// + protected ToggleButton SplitButtonToggleButton { get; set; } = null!; + + /// Identifies the dependency property. public static readonly DependencyProperty FlyoutProperty = DependencyProperty.Register( nameof(Flyout), typeof(object), typeof(SplitButton), - new PropertyMetadata(null, OnFlyoutChangedCallback) + new PropertyMetadata(null, OnFlyoutChanged) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register( nameof(IsDropDownOpen), typeof(bool), @@ -81,15 +77,17 @@ public SplitButton() }; } - private static void OnFlyoutChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void OnFlyoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is SplitButton dropDownButton) { - dropDownButton.OnFlyoutChangedCallback(e.NewValue); + dropDownButton.OnFlyoutChanged(e.NewValue); } } - protected virtual void OnFlyoutChangedCallback(object value) + /// This method is invoked when the changes. + /// The new value of . + protected virtual void OnFlyoutChanged(object value) { if (value is ContextMenu contextMenu) { @@ -103,7 +101,7 @@ private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyProper { if (d is SplitButton dropDownButton) { - dropDownButton.OnIsDropDownOpenChanged(e.NewValue is bool ? (bool)e.NewValue : false); + dropDownButton.OnIsDropDownOpenChanged(e.NewValue is bool boolVal && boolVal); } } @@ -117,6 +115,8 @@ protected virtual void OnContextMenuOpened(object sender, RoutedEventArgs e) SetCurrentValue(IsDropDownOpenProperty, true); } + /// This method is invoked when the changes. + /// The new value of . protected virtual void OnIsDropDownOpenChanged(bool currentValue) { } /// @@ -149,12 +149,7 @@ protected virtual void ReleaseTemplateResources() private void OnSplitButtonToggleButtonOnClick(object sender, RoutedEventArgs e) { - if (sender is not ToggleButton toggleButton) - { - return; - } - - if (_contextMenu is null) + if (sender is not ToggleButton || _contextMenu is null) { return; } diff --git a/source/RevitLookup.UI/Controls/SplitButton/SplitButton.xaml b/source/RevitLookup.UI/Controls/SplitButton/SplitButton.xaml index c70b241d7..dd3925b2d 100644 --- a/source/RevitLookup.UI/Controls/SplitButton/SplitButton.xaml +++ b/source/RevitLookup.UI/Controls/SplitButton/SplitButton.xaml @@ -126,7 +126,7 @@ CornerRadius="{TemplateBinding CornerRadius, Converter={StaticResource RightSplitCornerRadiusConverter}}"> -/// Represents a list of filled Fluent System Icons v.1.1.209. +/// Represents a list of filled Fluent System Icons v.1.1.233. /// May be converted to using GetGlyph() or to using GetString() /// -#pragma warning disable CS1591 public enum SymbolFilled { /// @@ -18,7 +17,6 @@ public enum SymbolFilled Empty = 0x0, // Automatically generated, may contain bugs. - AccessTime20 = 0xE000, Accessibility32 = 0xE001, Accessibility48 = 0xE002, @@ -7110,6 +7108,720 @@ public enum SymbolFilled VoicemailShield24 = 0xF02E0, VoicemailShield32 = 0xF02E1, WindowDatabase32 = 0xF02E2, + CastMultiple20 = 0xF02E3, + CastMultiple24 = 0xF02E4, + CastMultiple28 = 0xF02E5, + CircleHintHalfVertical16 = 0xF02E6, + CircleHintHalfVertical20 = 0xF02E7, + CircleHintHalfVertical24 = 0xF02E8, + FlashSparkle20 = 0xF02E9, + FlashSparkle24 = 0xF02EA, + Hexagon12 = 0xF02EB, + Hexagon24 = 0xF02EC, + HexagonThree12 = 0xF02ED, + HexagonThree24 = 0xF02EE, + NextFrame20 = 0xF02EF, + NextFrame24 = 0xF02F0, + PreviousFrame20 = 0xF02F1, + PreviousFrame24 = 0xF02F2, + TextboxAlignBottomCenter16 = 0xF02F3, + TextboxAlignBottomCenter20 = 0xF02F4, + TextboxAlignBottomCenter24 = 0xF02F5, + TextboxAlignBottomLeft16 = 0xF02F6, + TextboxAlignBottomLeft20 = 0xF02F7, + TextboxAlignBottomLeft24 = 0xF02F8, + TextboxAlignBottomRight16 = 0xF02F9, + TextboxAlignBottomRight20 = 0xF02FA, + TextboxAlignBottomRight24 = 0xF02FB, + TextboxAlignCenter16 = 0xF02FC, + TextboxAlignMiddleLeft16 = 0xF02FD, + TextboxAlignMiddleLeft20 = 0xF02FE, + TextboxAlignMiddleLeft24 = 0xF02FF, + TextboxAlignMiddleRight16 = 0xF0300, + TextboxAlignMiddleRight20 = 0xF0301, + TextboxAlignMiddleRight24 = 0xF0302, + TextboxAlignTopCenter16 = 0xF0303, + TextboxAlignTopCenter20 = 0xF0304, + TextboxAlignTopCenter24 = 0xF0305, + TextboxAlignTopLeft16 = 0xF0306, + TextboxAlignTopLeft20 = 0xF0307, + TextboxAlignTopLeft24 = 0xF0308, + TextboxAlignTopRight16 = 0xF0309, + TextboxAlignTopRight20 = 0xF030A, + TextboxAlignTopRight24 = 0xF030B, + TriangleDown24 = 0xF030C, + CallEnd12 = 0xF030D, + CallEnd32 = 0xF030E, + CallEnd48 = 0xF030F, + ContentViewGallery16 = 0xF0310, + ContentViewGalleryLightning16 = 0xF0311, + ContentViewGalleryLightning20 = 0xF0312, + ContentViewGalleryLightning24 = 0xF0313, + ContentViewGalleryLightning28 = 0xF0314, + GlobeArrowForward16 = 0xF0315, + GlobeArrowForward20 = 0xF0316, + GlobeArrowForward24 = 0xF0317, + GlobeArrowForward32 = 0xF0318, + HardDrive24 = 0xF0319, + HardDrive32 = 0xF031A, + HardDriveCall24 = 0xF031B, + HardDriveCall32 = 0xF031C, + MailRewind16 = 0xF031D, + MailRewind20 = 0xF031E, + MailRewind24 = 0xF031F, + PanelRightGallery16 = 0xF0320, + PanelRightGallery20 = 0xF0321, + PanelRightGallery24 = 0xF0322, + PanelRightGallery28 = 0xF0323, + PanelTopGallery16 = 0xF0324, + PanelTopGallery20 = 0xF0325, + PanelTopGallery24 = 0xF0326, + PanelTopGallery28 = 0xF0327, + RectangleLandscapeSparkle16 = 0xF0328, + RectangleLandscapeSparkle20 = 0xF0329, + RectangleLandscapeSparkle24 = 0xF032A, + RectangleLandscapeSparkle28 = 0xF032B, + RectangleLandscapeSparkle32 = 0xF032C, + ScanPerson16 = 0xF032D, + ScanPerson20 = 0xF032E, + ScanPerson24 = 0xF032F, + ScanPerson28 = 0xF0330, + ScanPerson48 = 0xF0331, + VoicemailShield16 = 0xF0332, + ChevronDown32 = 0xF0333, + ChevronLeft32 = 0xF0334, + ChevronRight32 = 0xF0335, + ChevronUp32 = 0xF0336, + DocumentLightning16 = 0xF0337, + DocumentLightning20 = 0xF0338, + DocumentLightning24 = 0xF0339, + DocumentLightning28 = 0xF033A, + DocumentLightning32 = 0xF033B, + DocumentLightning48 = 0xF033C, + Edit12 = 0xF033D, + ServerLink16 = 0xF033E, + ServerLink20 = 0xF033F, + Step20 = 0xF0340, + Step24 = 0xF0341, + TabDesktopMultipleAdd20 = 0xF0342, + TextDescription16 = 0xF0343, + TextDescription28 = 0xF0344, + TextDescription32 = 0xF0345, + TextGrammarLightning16 = 0xF0346, + TextGrammarLightning20 = 0xF0347, + TextGrammarLightning24 = 0xF0348, + TextGrammarLightning28 = 0xF0349, + TextGrammarLightning32 = 0xF034A, + BeakerAdd20 = 0xF034B, + BeakerAdd24 = 0xF034C, + BeakerDismiss20 = 0xF034D, + BeakerDismiss24 = 0xF034E, + DocumentCube20 = 0xF034F, + DocumentCube24 = 0xF0350, + Drawer20 = 0xF0351, + Drawer24 = 0xF0352, + FilmstripImage20 = 0xF0353, + FilmstripImage24 = 0xF0354, + NumberCircle016 = 0xF0355, + NumberCircle020 = 0xF0356, + NumberCircle024 = 0xF0357, + NumberCircle028 = 0xF0358, + NumberCircle032 = 0xF0359, + NumberCircle048 = 0xF035A, + NumberCircle616 = 0xF035B, + NumberCircle620 = 0xF035C, + NumberCircle624 = 0xF035D, + NumberCircle628 = 0xF035E, + NumberCircle632 = 0xF035F, + NumberCircle648 = 0xF0360, + NumberCircle716 = 0xF0361, + NumberCircle720 = 0xF0362, + NumberCircle724 = 0xF0363, + NumberCircle728 = 0xF0364, + NumberCircle732 = 0xF0365, + NumberCircle748 = 0xF0366, + NumberCircle816 = 0xF0367, + NumberCircle820 = 0xF0368, + NumberCircle824 = 0xF0369, + NumberCircle828 = 0xF036A, + NumberCircle832 = 0xF036B, + NumberCircle848 = 0xF036C, + NumberCircle916 = 0xF036D, + NumberCircle920 = 0xF036E, + NumberCircle924 = 0xF036F, + NumberCircle928 = 0xF0370, + NumberCircle932 = 0xF0371, + NumberCircle948 = 0xF0372, + Server12 = 0xF0373, + SquareHintHexagon12 = 0xF0374, + SquareHintHexagon16 = 0xF0375, + SquareHintHexagon20 = 0xF0376, + SquareHintHexagon24 = 0xF0377, + SquareHintHexagon28 = 0xF0378, + SquareHintHexagon32 = 0xF0379, + SquareHintHexagon48 = 0xF037A, + TabDesktopMultiple16 = 0xF037B, + TabDesktopMultipleAdd16 = 0xF037C, + TargetAdd20 = 0xF037D, + TargetAdd24 = 0xF037E, + TargetDismiss20 = 0xF037F, + TargetDismiss24 = 0xF0380, + TextHeader1Lines16 = 0xF0381, + TextHeader1Lines20 = 0xF0382, + TextHeader1Lines24 = 0xF0383, + TextHeader1LinesCaret16 = 0xF0384, + TextHeader1LinesCaret20 = 0xF0385, + TextHeader1LinesCaret24 = 0xF0386, + TextHeader2Lines16 = 0xF0387, + TextHeader2Lines20 = 0xF0388, + TextHeader2Lines24 = 0xF0389, + TextHeader2LinesCaret16 = 0xF038A, + TextHeader2LinesCaret20 = 0xF038B, + TextHeader2LinesCaret24 = 0xF038C, + TextHeader3Lines16 = 0xF038D, + TextHeader3Lines20 = 0xF038E, + TextHeader3Lines24 = 0xF038F, + TextHeader3LinesCaret16 = 0xF0390, + TextHeader3LinesCaret20 = 0xF0391, + TextHeader3LinesCaret24 = 0xF0392, + ArrowDownload28 = 0xF0393, + ArrowDownload32 = 0xF0394, + ArrowExpand16 = 0xF0395, + ArrowExportUp16 = 0xF0396, + ArrowImport16 = 0xF0397, + ArrowUpRightDashes16 = 0xF0398, + Battery1016 = 0xF0399, + BeakerEmpty16 = 0xF039A, + Book16 = 0xF039B, + BorderNone16 = 0xF039C, + BranchRequest16 = 0xF039D, + ClipboardTaskList16 = 0xF039E, + Cut16 = 0xF039F, + FolderSearch16 = 0xF03A0, + FolderSearch20 = 0xF03A1, + FolderSearch24 = 0xF03A2, + Hexagon28 = 0xF03A3, + Hexagon32 = 0xF03A4, + Hexagon48 = 0xF03A5, + PlugConnected16 = 0xF03A6, + PlugDisconnected16 = 0xF03A7, + ProjectionScreenText20 = 0xF03A8, + Rss16 = 0xF03A9, + ShapeOrganic16 = 0xF03AA, + ShapeOrganic20 = 0xF03AB, + ShapeOrganic24 = 0xF03AC, + ShapeOrganic28 = 0xF03AD, + ShapeOrganic32 = 0xF03AE, + ShapeOrganic48 = 0xF03AF, + TeardropBottomRight16 = 0xF03B0, + TeardropBottomRight20 = 0xF03B1, + TeardropBottomRight24 = 0xF03B2, + TeardropBottomRight28 = 0xF03B3, + TeardropBottomRight32 = 0xF03B4, + TeardropBottomRight48 = 0xF03B5, + TextEditStyle16 = 0xF03B6, + TextWholeWord16 = 0xF03B7, + Triangle24 = 0xF03B8, + Triangle28 = 0xF03B9, + TextAsterisk16 = 0xF03BA, + ArrowDownloadOff16 = 0xF03BB, + ArrowDownloadOff20 = 0xF03BC, + ArrowDownloadOff24 = 0xF03BD, + ArrowDownloadOff28 = 0xF03BE, + ArrowDownloadOff32 = 0xF03BF, + ArrowDownloadOff48 = 0xF03C0, + BorderInside16 = 0xF03C1, + BorderInside20 = 0xF03C2, + BorderInside24 = 0xF03C3, + ChatLock16 = 0xF03C4, + ChatLock20 = 0xF03C5, + ChatLock24 = 0xF03C6, + ChatLock28 = 0xF03C7, + ErrorCircle48 = 0xF03C8, + FullScreenMaximize28 = 0xF03C9, + FullScreenMaximize32 = 0xF03CA, + FullScreenMinimize28 = 0xF03CB, + FullScreenMinimize32 = 0xF03CC, + LinkPerson16 = 0xF03CD, + LinkPerson20 = 0xF03CE, + LinkPerson24 = 0xF03CF, + LinkPerson32 = 0xF03D0, + LinkPerson48 = 0xF03D1, + PeopleChat16 = 0xF03D2, + PeopleChat20 = 0xF03D3, + PeopleChat24 = 0xF03D4, + PersonSupport28 = 0xF03D5, + Shapes32 = 0xF03D6, + SlideTextEdit16 = 0xF03D7, + SlideTextEdit20 = 0xF03D8, + SlideTextEdit24 = 0xF03D9, + SlideTextEdit28 = 0xF03DA, + SubtractCircle48 = 0xF03DB, + SubtractParentheses16 = 0xF03DC, + SubtractParentheses20 = 0xF03DD, + SubtractParentheses24 = 0xF03DE, + SubtractParentheses28 = 0xF03DF, + SubtractParentheses32 = 0xF03E0, + SubtractParentheses48 = 0xF03E1, + Warning48 = 0xF03E2, + AlertOn16 = 0xF03E3, + ArrowDownExclamation16 = 0xF03E4, + ArrowDownExclamation20 = 0xF03E5, + ArrowFit24 = 0xF03E6, + ArrowFitIn24 = 0xF03E7, + Book32 = 0xF03E8, + BookDatabase16 = 0xF03E9, + BookDatabase32 = 0xF03EA, + BookToolbox16 = 0xF03EB, + BuildingDesktop32 = 0xF03EC, + BuildingGovernment16 = 0xF03ED, + BuildingGovernmentSearch16 = 0xF03EE, + BuildingGovernmentSearch20 = 0xF03EF, + BuildingGovernmentSearch24 = 0xF03F0, + BuildingGovernmentSearch32 = 0xF03F1, + CalendarRecord16 = 0xF03F2, + CalendarRecord20 = 0xF03F3, + CalendarRecord24 = 0xF03F4, + CalendarRecord28 = 0xF03F5, + CalendarRecord32 = 0xF03F6, + CalendarRecord48 = 0xF03F7, + Clipboard28 = 0xF03F8, + ClipboardMathFormula16 = 0xF03F9, + ClipboardMathFormula20 = 0xF03FA, + ClipboardMathFormula24 = 0xF03FB, + ClipboardMathFormula28 = 0xF03FC, + ClipboardMathFormula32 = 0xF03FD, + ClipboardNumber12316 = 0xF03FE, + ClipboardNumber12320 = 0xF03FF, + ClipboardNumber12324 = 0xF0400, + ClipboardNumber12328 = 0xF0401, + ClipboardNumber12332 = 0xF0402, + Collections16 = 0xF0403, + CommunicationShield16 = 0xF0404, + CommunicationShield20 = 0xF0405, + CommunicationShield24 = 0xF0406, + DialpadQuestionMark20 = 0xF0407, + DialpadQuestionMark24 = 0xF0408, + DocumentBriefcase16 = 0xF0409, + DocumentBriefcase32 = 0xF040A, + DocumentSearch32 = 0xF040B, + Fingerprint16 = 0xF040C, + Fingerprint32 = 0xF040D, + FolderPerson24 = 0xF040E, + FolderPerson28 = 0xF040F, + FolderPerson32 = 0xF0410, + FolderPerson48 = 0xF0411, + HatGraduationAdd16 = 0xF0412, + HatGraduationAdd20 = 0xF0413, + HatGraduationAdd24 = 0xF0414, + LayerDiagonalAdd20 = 0xF0415, + Library32 = 0xF0416, + LightbulbFilament32 = 0xF0417, + LinkAdd16 = 0xF0418, + LinkAdd20 = 0xF0419, + LockShield16 = 0xF041A, + LockShield28 = 0xF041B, + LockShield32 = 0xF041C, + PersonVoice16 = 0xF041D, + PersonWarning16 = 0xF041E, + PersonWarning20 = 0xF041F, + PersonWarning24 = 0xF0420, + PersonWarning28 = 0xF0421, + PersonWarning32 = 0xF0422, + PersonWarning48 = 0xF0423, + ScanTypeOff24 = 0xF0424, + Screenshot16 = 0xF0425, + ScreenshotRecord16 = 0xF0426, + ScreenshotRecord20 = 0xF0427, + ScreenshotRecord24 = 0xF0428, + SlideSearch16 = 0xF0429, + SlideSearch32 = 0xF042A, + VehicleSubwayClock16 = 0xF042B, + VehicleSubwayClock20 = 0xF042C, + VehicleSubwayClock24 = 0xF042D, + VideoClipOptimize16 = 0xF042E, + VideoClipOptimize20 = 0xF042F, + VideoClipOptimize24 = 0xF0430, + VideoClipOptimize28 = 0xF0431, + VideoPersonPulse16 = 0xF0432, + VideoPersonPulse20 = 0xF0433, + VideoPersonPulse24 = 0xF0434, + VideoPersonPulse28 = 0xF0435, + ArchiveSettings32 = 0xF0436, + ArrowForward32 = 0xF0437, + ArrowReply32 = 0xF0438, + ArrowReplyAll32 = 0xF0439, + Attach32 = 0xF043A, + Autocorrect32 = 0xF043B, + Broom32 = 0xF043C, + CalendarNote16 = 0xF043D, + CalendarNote20 = 0xF043E, + CalendarNote24 = 0xF043F, + CalendarNote32 = 0xF0440, + CheckmarkUnderlineCircle24 = 0xF0441, + DataBarVerticalAscending20 = 0xF0442, + DataBarVerticalAscending24 = 0xF0443, + Diversity16 = 0xF0444, + Filter32 = 0xF0445, + FolderMail32 = 0xF0446, + GlanceHorizontal32 = 0xF0447, + GlanceHorizontalSparkle32 = 0xF0448, + GlobeArrowUp16 = 0xF0449, + GlobeArrowUp20 = 0xF044A, + GlobeArrowUp24 = 0xF044B, + GlobeError16 = 0xF044C, + GlobeError20 = 0xF044D, + GlobeError24 = 0xF044E, + GlobeProhibited16 = 0xF044F, + GlobeProhibited24 = 0xF0450, + GlobeSync16 = 0xF0451, + GlobeSync20 = 0xF0452, + GlobeSync24 = 0xF0453, + GlobeWarning16 = 0xF0454, + GlobeWarning20 = 0xF0455, + GlobeWarning24 = 0xF0456, + Important32 = 0xF0457, + LayerDiagonal16 = 0xF0458, + LayerDiagonalPerson16 = 0xF0459, + MailMultiple32 = 0xF045A, + MailRead32 = 0xF045B, + MailUnread32 = 0xF045C, + Mailbox16 = 0xF045D, + Mailbox20 = 0xF045E, + OrganizationHorizontal16 = 0xF045F, + OrganizationHorizontal24 = 0xF0460, + PeopleList32 = 0xF0461, + PersonAdd32 = 0xF0462, + PersonSquare16 = 0xF0463, + PersonSquare32 = 0xF0464, + PersonSquareCheckmark16 = 0xF0465, + PersonSquareCheckmark20 = 0xF0466, + PersonSquareCheckmark24 = 0xF0467, + PersonSquareCheckmark32 = 0xF0468, + PhoneFooterArrowDown20 = 0xF0469, + PhoneFooterArrowDown24 = 0xF046A, + PhoneHeaderArrowUp20 = 0xF046B, + PhoneHeaderArrowUp24 = 0xF046C, + Poll32 = 0xF046D, + Question32 = 0xF046E, + Screenshot28 = 0xF046F, + ScreenshotRecord28 = 0xF0470, + Star32 = 0xF0471, + TextDensity32 = 0xF0472, + TextEditStyleCharacterA32 = 0xF0473, + WrenchScrewdriver32 = 0xF0474, + ArrowClockwiseDashes16 = 0xF0475, + ArrowClockwiseDashes32 = 0xF0476, + BuildingSwap16 = 0xF0477, + BuildingSwap20 = 0xF0478, + BuildingSwap24 = 0xF0479, + BuildingSwap32 = 0xF047A, + BuildingSwap48 = 0xF047B, + Certificate32 = 0xF047C, + ClipboardBrush16 = 0xF047D, + ClipboardBrush20 = 0xF047E, + ClipboardBrush24 = 0xF047F, + ClipboardBrush28 = 0xF0480, + ClipboardBrush32 = 0xF0481, + CloudBeaker16 = 0xF0482, + CloudBeaker20 = 0xF0483, + CloudBeaker24 = 0xF0484, + CloudBeaker28 = 0xF0485, + CloudBeaker32 = 0xF0486, + CloudBeaker48 = 0xF0487, + CloudCube16 = 0xF0488, + CloudCube20 = 0xF0489, + CloudCube24 = 0xF048A, + CloudCube28 = 0xF048B, + CloudCube32 = 0xF048C, + CloudCube48 = 0xF048D, + ContractUpRight16 = 0xF048E, + ContractUpRight20 = 0xF048F, + ContractUpRight24 = 0xF0490, + ContractUpRight28 = 0xF0491, + ContractUpRight32 = 0xF0492, + ContractUpRight48 = 0xF0493, + DocumentDataLock16 = 0xF0494, + DocumentDataLock20 = 0xF0495, + DocumentDataLock24 = 0xF0496, + DocumentDataLock32 = 0xF0497, + GlanceHorizontalSparkles20 = 0xF0498, + LayoutCellFour16 = 0xF0499, + LayoutCellFour20 = 0xF049A, + LayoutCellFour24 = 0xF049B, + LayoutColumnFour16 = 0xF04A8, + LayoutColumnFour20 = 0xF04A9, + LayoutColumnFour24 = 0xF04AA, + LayoutColumnOneThirdLeft16 = 0xF04B7, + LayoutColumnOneThirdLeft20 = 0xF04B8, + LayoutColumnOneThirdLeft24 = 0xF04B9, + LayoutColumnOneThirdRight16 = 0xF04BA, + LayoutColumnOneThirdRight20 = 0xF04BB, + LayoutColumnOneThirdRight24 = 0xF04BC, + LayoutColumnOneThirdRightHint16 = 0xF04BD, + LayoutColumnOneThirdRightHint20 = 0xF04BE, + LayoutColumnOneThirdRightHint24 = 0xF04BF, + LayoutColumnThree16 = 0xF04C0, + LayoutColumnThree20 = 0xF04C1, + LayoutColumnThree24 = 0xF04C2, + LayoutColumnTwo16 = 0xF04CC, + LayoutColumnTwo20 = 0xF04CD, + LayoutColumnTwo24 = 0xF04CE, + LayoutColumnTwoSplitLeft16 = 0xF04D5, + LayoutColumnTwoSplitLeft20 = 0xF04D6, + LayoutColumnTwoSplitLeft24 = 0xF04D7, + LayoutColumnTwoSplitRight16 = 0xF04E1, + LayoutColumnTwoSplitRight20 = 0xF04E2, + LayoutColumnTwoSplitRight24 = 0xF04E3, + LayoutRowFour16 = 0xF04ED, + LayoutRowFour20 = 0xF04EE, + LayoutRowFour24 = 0xF04EF, + LayoutRowThree16 = 0xF04FC, + LayoutRowThree20 = 0xF04FD, + LayoutRowThree24 = 0xF04FE, + LayoutRowTwo16 = 0xF0508, + LayoutRowTwo20 = 0xF0509, + LayoutRowTwo24 = 0xF050A, + LayoutRowTwoSplitBottom16 = 0xF0511, + LayoutRowTwoSplitBottom20 = 0xF0512, + LayoutRowTwoSplitBottom24 = 0xF0513, + LayoutRowTwoSplitTop16 = 0xF051D, + LayoutRowTwoSplitTop20 = 0xF051E, + LayoutRowTwoSplitTop24 = 0xF051F, + LocationTargetSquare16 = 0xF0529, + LocationTargetSquare20 = 0xF052A, + LocationTargetSquare24 = 0xF052B, + LocationTargetSquare32 = 0xF052C, + Resize16 = 0xF052D, + Resize28 = 0xF052E, + Resize32 = 0xF052F, + Resize48 = 0xF0530, + SelectAllOff16 = 0xF0531, + SelectAllOn16 = 0xF0532, + ShareAndroid16 = 0xF0533, + ShareAndroid32 = 0xF0534, + TextArrowDownRightColumn16 = 0xF0535, + TextArrowDownRightColumn20 = 0xF0536, + TextArrowDownRightColumn24 = 0xF0537, + TextArrowDownRightColumn28 = 0xF0538, + TextArrowDownRightColumn32 = 0xF0539, + TextArrowDownRightColumn48 = 0xF053A, + TextEffectsSparkle20 = 0xF053B, + TextEffectsSparkle24 = 0xF053C, + Whiteboard16 = 0xF053D, + WhiteboardOff16 = 0xF053E, + WhiteboardOff20 = 0xF053F, + WhiteboardOff24 = 0xF0540, + Flowchart16 = 0xF0541, + Flowchart32 = 0xF0542, + LayerDiagonal24 = 0xF0543, + LayerDiagonalPerson24 = 0xF0544, + PollOff16 = 0xF0545, + PollOff20 = 0xF0546, + PollOff24 = 0xF0547, + PollOff32 = 0xF0548, + RectangleLandscapeSparkle48 = 0xF0549, + RectangleLandscapeSync16 = 0xF054A, + RectangleLandscapeSync20 = 0xF054B, + RectangleLandscapeSync24 = 0xF054C, + RectangleLandscapeSync28 = 0xF054D, + RectangleLandscapeSyncOff16 = 0xF054E, + RectangleLandscapeSyncOff20 = 0xF054F, + RectangleLandscapeSyncOff24 = 0xF0550, + RectangleLandscapeSyncOff28 = 0xF0551, + Seat16 = 0xF0552, + Seat20 = 0xF0553, + Seat24 = 0xF0554, + SeatAdd16 = 0xF0555, + SeatAdd20 = 0xF0556, + SeatAdd24 = 0xF0557, + SpeakerBox16 = 0xF0558, + SpeakerBox20 = 0xF0559, + SpeakerBox24 = 0xF055A, + TextEditStyleCharacterGa32 = 0xF055B, + WindowAd24 = 0xF055C, + WrenchSettings20 = 0xF055D, + WrenchSettings24 = 0xF055E, + BuildingLighthouse24 = 0xF055F, + BuildingLighthouse32 = 0xF0560, + BuildingLighthouse48 = 0xF0561, + CalendarLink24 = 0xF0562, + CalendarLink28 = 0xF0563, + CalendarVideo24 = 0xF0564, + CalendarVideo28 = 0xF0565, + Cookies16 = 0xF0566, + Cookies28 = 0xF0567, + Cookies32 = 0xF0568, + Cookies48 = 0xF0569, + HardDrive28 = 0xF056A, + HardDrive48 = 0xF056B, + Laptop32 = 0xF056C, + LaptopSettings20 = 0xF056D, + LaptopSettings24 = 0xF056E, + LaptopSettings32 = 0xF056F, + PeopleAudience32 = 0xF0570, + ShoppingBagAdd20 = 0xF0571, + ShoppingBagAdd24 = 0xF0572, + StreetSign20 = 0xF0573, + StreetSign24 = 0xF0574, + VideoLink24 = 0xF0575, + VideoLink28 = 0xF0576, + BuildingLighthouse16 = 0xF0577, + CalendarSparkle16 = 0xF0578, + CalendarSparkle20 = 0xF0579, + CalendarSparkle24 = 0xF057A, + CalendarSparkle28 = 0xF057B, + CalendarSparkle32 = 0xF057C, + CalendarSparkle48 = 0xF057D, + CalendarTemplate20 = 0xF057E, + CalendarTemplate24 = 0xF057F, + CalendarTemplate32 = 0xF0580, + Clipboard12 = 0xF0581, + Clipboard48 = 0xF0582, + Compose12 = 0xF0583, + Compose32 = 0xF0584, + Compose48 = 0xF0585, + Globe28 = 0xF0586, + Guest12 = 0xF0587, + Guest32 = 0xF0588, + Guest48 = 0xF0589, + LaptopBriefcase20 = 0xF058A, + LaptopBriefcase24 = 0xF058B, + LaptopBriefcase32 = 0xF058C, + LayerDiagonalSparkle16 = 0xF058D, + LayerDiagonalSparkle20 = 0xF058E, + LayerDiagonalSparkle24 = 0xF058F, + PaymentWireless16 = 0xF0590, + PaymentWireless20 = 0xF0591, + PaymentWireless24 = 0xF0592, + PaymentWireless28 = 0xF0593, + PaymentWireless32 = 0xF0594, + PaymentWireless48 = 0xF0595, + Status28 = 0xF0596, + Status32 = 0xF0597, + Status48 = 0xF0598, + VideoOff16 = 0xF0599, + CheckmarkCircleWarning16 = 0xF059A, + CheckmarkCircleWarning20 = 0xF059B, + CheckmarkCircleWarning24 = 0xF059C, + CloudArrowRight16 = 0xF059D, + CloudArrowRight20 = 0xF059E, + CloudArrowRight24 = 0xF059F, + DocumentArrowDown24 = 0xF05A0, + DocumentSignature16 = 0xF05A1, + DocumentSignature20 = 0xF05A2, + DocumentSignature24 = 0xF05A3, + DocumentSignature28 = 0xF05A4, + DocumentSignature32 = 0xF05A5, + DocumentSignature48 = 0xF05A6, + HomeGarage20 = 0xF05A7, + HomeGarage24 = 0xF05A8, + ImageSplit20 = 0xF05A9, + ImageSplit24 = 0xF05AA, + Laptop48 = 0xF05AB, + LineFlowDiagonalUpRight16 = 0xF05AC, + LineFlowDiagonalUpRight20 = 0xF05AD, + LineFlowDiagonalUpRight24 = 0xF05AE, + LineFlowDiagonalUpRight32 = 0xF05AF, + MailArrowClockwise16 = 0xF05B0, + MailArrowClockwise20 = 0xF05B1, + MailArrowClockwise24 = 0xF05B2, + PersonPasskey16 = 0xF05B3, + PersonPasskey20 = 0xF05B4, + PersonPasskey24 = 0xF05B5, + PersonPasskey28 = 0xF05B6, + PersonPasskey32 = 0xF05B7, + PersonPasskey48 = 0xF05B8, + PersonProhibited32 = 0xF05B9, + PersonRibbon24 = 0xF05BA, + PlantCattail20 = 0xF05BB, + PlantCattail24 = 0xF05BC, + Storage16 = 0xF05BD, + Storage28 = 0xF05BE, + Storage32 = 0xF05BF, + Storage48 = 0xF05C0, + VideoClipWand16 = 0xF05C1, + VideoClipWand20 = 0xF05C2, + VideoClipWand24 = 0xF05C3, + WindowFingerprint16 = 0xF05C4, + WindowFingerprint20 = 0xF05C5, + WindowFingerprint24 = 0xF05C6, + WindowFingerprint28 = 0xF05C7, + WindowFingerprint32 = 0xF05C8, + WindowFingerprint48 = 0xF05C9, + AccessibilityError20 = 0xF05CA, + AccessibilityError24 = 0xF05CB, + AccessibilityQuestionMark20 = 0xF05CC, + AccessibilityQuestionMark24 = 0xF05CD, + ArrowDownExclamation24 = 0xF05CE, + ArrowSortUpLines16 = 0xF05CF, + ArrowSortUpLines20 = 0xF05D0, + ArrowSortUpLines24 = 0xF05D1, + ArrowUpExclamation16 = 0xF05D2, + ArrowUpExclamation20 = 0xF05D3, + ArrowUpExclamation24 = 0xF05D4, + Bench20 = 0xF05D5, + Bench24 = 0xF05D6, + BuildingLighthouse28 = 0xF05D7, + CalendarVideo20 = 0xF05D8, + ClockBill16 = 0xF05D9, + ClockBill20 = 0xF05DA, + ClockBill24 = 0xF05DB, + ClockBill32 = 0xF05DC, + DataUsage16 = 0xF05DD, + DataUsageSettings16 = 0xF05DE, + DataUsageSettings24 = 0xF05DF, + EditPerson20 = 0xF05E0, + EditPerson24 = 0xF05E1, + Highway20 = 0xF05E2, + Highway24 = 0xF05E3, + LaptopPerson20 = 0xF05E4, + LaptopPerson24 = 0xF05E5, + LaptopPerson48 = 0xF05E6, + LocationRipple16 = 0xF05E7, + LocationRipple20 = 0xF05E8, + LocationRipple24 = 0xF05E9, + MailArrowDoubleBack32 = 0xF05EA, + MailBriefcase48 = 0xF05EB, + Options28 = 0xF05EC, + Options32 = 0xF05ED, + PeopleAdd32 = 0xF05EE, + PersonAlert32 = 0xF05EF, + Road20 = 0xF05F0, + Road24 = 0xF05F1, + Save32 = 0xF05F2, + TabDesktopMultiple24 = 0xF05F3, + TabDesktopMultipleSparkle16 = 0xF05F4, + TabDesktopMultipleSparkle20 = 0xF05F5, + TabDesktopMultipleSparkle24 = 0xF05F6, + VehicleTractor20 = 0xF05F7, + VehicleTractor24 = 0xF05F8, + Classification32 = 0xF05F9, + DocumentTarget20 = 0xF05FA, + DocumentTarget24 = 0xF05FB, + DocumentTarget32 = 0xF05FC, + EmojiMeme16 = 0xF05FD, + EmojiMeme20 = 0xF05FE, + EmojiMeme24 = 0xF05FF, + HandPoint16 = 0xF0600, + HandPoint20 = 0xF0601, + HandPoint24 = 0xF0602, + HandPoint28 = 0xF0603, + HandPoint32 = 0xF0604, + HandPoint48 = 0xF0605, + MailReadBriefcase48 = 0xF0606, + PeopleSubtract20 = 0xF0607, + PeopleSubtract24 = 0xF0608, + PeopleSubtract32 = 0xF0609, + PersonAlertOff16 = 0xF060A, + PersonAlertOff20 = 0xF060B, + PersonAlertOff24 = 0xF060C, + PersonAlertOff32 = 0xF060D, + ShoppingBagAdd16 = 0xF060E, + SpatulaSpoon16 = 0xF060F, + SpatulaSpoon20 = 0xF0610, + SpatulaSpoon24 = 0xF0611, + SpatulaSpoon28 = 0xF0612, + SpatulaSpoon32 = 0xF0613, + SpatulaSpoon48 = 0xF0614, } - -#pragma warning restore CS1591 diff --git a/source/RevitLookup.UI/Controls/SymbolGlyph.cs b/source/RevitLookup.UI/Controls/SymbolGlyph.cs index 172fd729f..227cd2bae 100644 --- a/source/RevitLookup.UI/Controls/SymbolGlyph.cs +++ b/source/RevitLookup.UI/Controls/SymbolGlyph.cs @@ -26,14 +26,16 @@ public static class SymbolGlyph /// Name of the icon. public static SymbolRegular Parse(string name) { - if (String.IsNullOrEmpty(name)) + if (string.IsNullOrEmpty(name)) + { return DefaultIcon; + } try { return (SymbolRegular)Enum.Parse(typeof(SymbolRegular), name); } - catch (Exception _) + catch (Exception) { #if DEBUG throw; @@ -49,14 +51,16 @@ public static SymbolRegular Parse(string name) /// Name of the icon. public static SymbolFilled ParseFilled(string name) { - if (String.IsNullOrEmpty(name)) + if (string.IsNullOrEmpty(name)) + { return DefaultFilledIcon; + } try { return (SymbolFilled)Enum.Parse(typeof(SymbolFilled), name); } - catch (Exception e) + catch (Exception) { #if DEBUG throw; diff --git a/source/RevitLookup.UI/Controls/SymbolRegular.cs b/source/RevitLookup.UI/Controls/SymbolRegular.cs index 1661da932..a60740fa4 100644 --- a/source/RevitLookup.UI/Controls/SymbolRegular.cs +++ b/source/RevitLookup.UI/Controls/SymbolRegular.cs @@ -6,10 +6,9 @@ namespace Wpf.Ui.Controls; /// -/// Represents a list of regular Fluent System Icons v.1.1.209. +/// Represents a list of regular Fluent System Icons v.1.1.233. /// May be converted to using GetGlyph() or to using GetString() /// -#pragma warning disable CS1591 public enum SymbolRegular { /// @@ -18,7 +17,6 @@ public enum SymbolRegular Empty = 0x0, // Automatically generated, may contain bugs. - AccessTime20 = 0xE000, Accessibility32 = 0xE001, Accessibility48 = 0xE002, @@ -7110,6 +7108,720 @@ public enum SymbolRegular VoicemailShield24 = 0xF02CD, VoicemailShield32 = 0xF02CE, WindowDatabase32 = 0xF02CF, + CastMultiple20 = 0xF02D0, + CastMultiple24 = 0xF02D1, + CastMultiple28 = 0xF02D2, + CircleHintHalfVertical16 = 0xF02D3, + CircleHintHalfVertical20 = 0xF02D4, + CircleHintHalfVertical24 = 0xF02D5, + FlashSparkle20 = 0xF02D6, + FlashSparkle24 = 0xF02D7, + Hexagon12 = 0xF02D8, + Hexagon24 = 0xF02D9, + HexagonThree12 = 0xF02DA, + HexagonThree24 = 0xF02DB, + NextFrame20 = 0xF02DC, + NextFrame24 = 0xF02DD, + PreviousFrame20 = 0xF02DE, + PreviousFrame24 = 0xF02DF, + TextboxAlignBottomCenter16 = 0xF02E0, + TextboxAlignBottomCenter20 = 0xF02E1, + TextboxAlignBottomCenter24 = 0xF02E2, + TextboxAlignBottomLeft16 = 0xF02E3, + TextboxAlignBottomLeft20 = 0xF02E4, + TextboxAlignBottomLeft24 = 0xF02E5, + TextboxAlignBottomRight16 = 0xF02E6, + TextboxAlignBottomRight20 = 0xF02E7, + TextboxAlignBottomRight24 = 0xF02E8, + TextboxAlignCenter16 = 0xF02E9, + TextboxAlignMiddleLeft16 = 0xF02EA, + TextboxAlignMiddleLeft20 = 0xF02EB, + TextboxAlignMiddleLeft24 = 0xF02EC, + TextboxAlignMiddleRight16 = 0xF02ED, + TextboxAlignMiddleRight20 = 0xF02EE, + TextboxAlignMiddleRight24 = 0xF02EF, + TextboxAlignTopCenter16 = 0xF02F0, + TextboxAlignTopCenter20 = 0xF02F1, + TextboxAlignTopCenter24 = 0xF02F2, + TextboxAlignTopLeft16 = 0xF02F3, + TextboxAlignTopLeft20 = 0xF02F4, + TextboxAlignTopLeft24 = 0xF02F5, + TextboxAlignTopRight16 = 0xF02F6, + TextboxAlignTopRight20 = 0xF02F7, + TextboxAlignTopRight24 = 0xF02F8, + TriangleDown24 = 0xF02F9, + CallEnd12 = 0xF02FA, + CallEnd32 = 0xF02FB, + CallEnd48 = 0xF02FC, + ContentViewGallery16 = 0xF02FD, + ContentViewGalleryLightning16 = 0xF02FE, + ContentViewGalleryLightning20 = 0xF02FF, + ContentViewGalleryLightning24 = 0xF0300, + ContentViewGalleryLightning28 = 0xF0301, + GlobeArrowForward16 = 0xF0302, + GlobeArrowForward20 = 0xF0303, + GlobeArrowForward24 = 0xF0304, + GlobeArrowForward32 = 0xF0305, + HardDrive24 = 0xF0306, + HardDrive32 = 0xF0307, + HardDriveCall24 = 0xF0308, + HardDriveCall32 = 0xF0309, + MailRewind16 = 0xF030A, + MailRewind20 = 0xF030B, + MailRewind24 = 0xF030C, + PanelRightGallery16 = 0xF030D, + PanelRightGallery20 = 0xF030E, + PanelRightGallery24 = 0xF030F, + PanelRightGallery28 = 0xF0310, + PanelTopGallery16 = 0xF0311, + PanelTopGallery20 = 0xF0312, + PanelTopGallery24 = 0xF0313, + PanelTopGallery28 = 0xF0314, + RectangleLandscapeSparkle16 = 0xF0315, + RectangleLandscapeSparkle20 = 0xF0316, + RectangleLandscapeSparkle24 = 0xF0317, + RectangleLandscapeSparkle28 = 0xF0318, + RectangleLandscapeSparkle32 = 0xF0319, + ScanPerson16 = 0xF031A, + ScanPerson20 = 0xF031B, + ScanPerson24 = 0xF031C, + ScanPerson28 = 0xF031D, + ScanPerson48 = 0xF031E, + VoicemailShield16 = 0xF031F, + ChevronDown32 = 0xF0320, + ChevronLeft32 = 0xF0321, + ChevronRight32 = 0xF0322, + ChevronUp32 = 0xF0323, + DocumentLightning16 = 0xF0324, + DocumentLightning20 = 0xF0325, + DocumentLightning24 = 0xF0326, + DocumentLightning28 = 0xF0327, + DocumentLightning32 = 0xF0328, + DocumentLightning48 = 0xF0329, + Edit12 = 0xF032A, + ServerLink16 = 0xF032B, + ServerLink20 = 0xF032C, + Step20 = 0xF032D, + Step24 = 0xF032E, + TabDesktopMultipleAdd20 = 0xF032F, + TextDescription16 = 0xF0330, + TextDescription28 = 0xF0331, + TextDescription32 = 0xF0332, + TextGrammarLightning16 = 0xF0333, + TextGrammarLightning20 = 0xF0334, + TextGrammarLightning24 = 0xF0335, + TextGrammarLightning28 = 0xF0336, + TextGrammarLightning32 = 0xF0337, + BeakerAdd20 = 0xF0338, + BeakerAdd24 = 0xF0339, + BeakerDismiss20 = 0xF033A, + BeakerDismiss24 = 0xF033B, + DocumentCube20 = 0xF033C, + DocumentCube24 = 0xF033D, + Drawer20 = 0xF033E, + Drawer24 = 0xF033F, + FilmstripImage20 = 0xF0340, + FilmstripImage24 = 0xF0341, + NumberCircle016 = 0xF0342, + NumberCircle020 = 0xF0343, + NumberCircle024 = 0xF0344, + NumberCircle028 = 0xF0345, + NumberCircle032 = 0xF0346, + NumberCircle048 = 0xF0347, + NumberCircle616 = 0xF0348, + NumberCircle620 = 0xF0349, + NumberCircle624 = 0xF034A, + NumberCircle628 = 0xF034B, + NumberCircle632 = 0xF034C, + NumberCircle648 = 0xF034D, + NumberCircle716 = 0xF034E, + NumberCircle720 = 0xF034F, + NumberCircle724 = 0xF0350, + NumberCircle728 = 0xF0351, + NumberCircle732 = 0xF0352, + NumberCircle748 = 0xF0353, + NumberCircle816 = 0xF0354, + NumberCircle820 = 0xF0355, + NumberCircle824 = 0xF0356, + NumberCircle828 = 0xF0357, + NumberCircle832 = 0xF0358, + NumberCircle848 = 0xF0359, + NumberCircle916 = 0xF035A, + NumberCircle920 = 0xF035B, + NumberCircle924 = 0xF035C, + NumberCircle928 = 0xF035D, + NumberCircle932 = 0xF035E, + NumberCircle948 = 0xF035F, + Server12 = 0xF0360, + SquareHintHexagon12 = 0xF0361, + SquareHintHexagon16 = 0xF0362, + SquareHintHexagon20 = 0xF0363, + SquareHintHexagon24 = 0xF0364, + SquareHintHexagon28 = 0xF0365, + SquareHintHexagon32 = 0xF0366, + SquareHintHexagon48 = 0xF0367, + TabDesktopMultiple16 = 0xF0368, + TabDesktopMultipleAdd16 = 0xF0369, + TargetAdd20 = 0xF036A, + TargetAdd24 = 0xF036B, + TargetDismiss20 = 0xF036C, + TargetDismiss24 = 0xF036D, + TextHeader1Lines16 = 0xF036E, + TextHeader1Lines20 = 0xF036F, + TextHeader1Lines24 = 0xF0370, + TextHeader1LinesCaret16 = 0xF0371, + TextHeader1LinesCaret20 = 0xF0372, + TextHeader1LinesCaret24 = 0xF0373, + TextHeader2Lines16 = 0xF0374, + TextHeader2Lines20 = 0xF0375, + TextHeader2Lines24 = 0xF0376, + TextHeader2LinesCaret16 = 0xF0377, + TextHeader2LinesCaret20 = 0xF0378, + TextHeader2LinesCaret24 = 0xF0379, + TextHeader3Lines16 = 0xF037A, + TextHeader3Lines20 = 0xF037B, + TextHeader3Lines24 = 0xF037C, + TextHeader3LinesCaret16 = 0xF037D, + TextHeader3LinesCaret20 = 0xF037E, + TextHeader3LinesCaret24 = 0xF037F, + ArrowDownload28 = 0xF0380, + ArrowDownload32 = 0xF0381, + ArrowExpand16 = 0xF0382, + ArrowExportUp16 = 0xF0383, + ArrowImport16 = 0xF0384, + ArrowUpRightDashes16 = 0xF0385, + Battery1016 = 0xF0386, + BeakerEmpty16 = 0xF0387, + Book16 = 0xF0388, + BorderNone16 = 0xF0389, + BranchRequest16 = 0xF038A, + ClipboardTaskList16 = 0xF038B, + Cut16 = 0xF038C, + FolderSearch16 = 0xF038D, + FolderSearch20 = 0xF038E, + FolderSearch24 = 0xF038F, + Hexagon28 = 0xF0390, + Hexagon32 = 0xF0391, + Hexagon48 = 0xF0392, + PlugConnected16 = 0xF0393, + PlugDisconnected16 = 0xF0394, + ProjectionScreenText20 = 0xF0395, + Rss16 = 0xF0396, + ShapeOrganic16 = 0xF0397, + ShapeOrganic20 = 0xF0398, + ShapeOrganic24 = 0xF0399, + ShapeOrganic28 = 0xF039A, + ShapeOrganic32 = 0xF039B, + ShapeOrganic48 = 0xF039C, + TeardropBottomRight16 = 0xF039D, + TeardropBottomRight20 = 0xF039E, + TeardropBottomRight24 = 0xF039F, + TeardropBottomRight28 = 0xF03A0, + TeardropBottomRight32 = 0xF03A1, + TeardropBottomRight48 = 0xF03A2, + TextEditStyle16 = 0xF03A3, + TextWholeWord16 = 0xF03A4, + Triangle24 = 0xF03A5, + Triangle28 = 0xF03A6, + TextAsterisk16 = 0xF03A7, + ArrowDownloadOff16 = 0xF03A8, + ArrowDownloadOff20 = 0xF03A9, + ArrowDownloadOff24 = 0xF03AA, + ArrowDownloadOff28 = 0xF03AB, + ArrowDownloadOff32 = 0xF03AC, + ArrowDownloadOff48 = 0xF03AD, + BorderInside16 = 0xF03AE, + BorderInside20 = 0xF03AF, + BorderInside24 = 0xF03B0, + ChatLock16 = 0xF03B1, + ChatLock20 = 0xF03B2, + ChatLock24 = 0xF03B3, + ChatLock28 = 0xF03B4, + ErrorCircle48 = 0xF03B5, + FullScreenMaximize28 = 0xF03B6, + FullScreenMaximize32 = 0xF03B7, + FullScreenMinimize28 = 0xF03B8, + FullScreenMinimize32 = 0xF03B9, + LinkPerson16 = 0xF03BA, + LinkPerson20 = 0xF03BB, + LinkPerson24 = 0xF03BC, + LinkPerson32 = 0xF03BD, + LinkPerson48 = 0xF03BE, + PeopleChat16 = 0xF03BF, + PeopleChat20 = 0xF03C0, + PeopleChat24 = 0xF03C1, + PersonSupport28 = 0xF03C2, + Shapes32 = 0xF03C3, + SlideTextEdit16 = 0xF03C4, + SlideTextEdit20 = 0xF03C5, + SlideTextEdit24 = 0xF03C6, + SlideTextEdit28 = 0xF03C7, + SubtractCircle48 = 0xF03C8, + SubtractParentheses16 = 0xF03C9, + SubtractParentheses20 = 0xF03CA, + SubtractParentheses24 = 0xF03CB, + SubtractParentheses28 = 0xF03CC, + SubtractParentheses32 = 0xF03CD, + SubtractParentheses48 = 0xF03CE, + Warning48 = 0xF03CF, + AlertOn16 = 0xF03D0, + ArrowDownExclamation16 = 0xF03D1, + ArrowDownExclamation20 = 0xF03D2, + ArrowFit24 = 0xF03D3, + ArrowFitIn24 = 0xF03D4, + Book32 = 0xF03D5, + BookDatabase16 = 0xF03D6, + BookDatabase32 = 0xF03D7, + BookToolbox16 = 0xF03D8, + BuildingDesktop32 = 0xF03D9, + BuildingGovernment16 = 0xF03DA, + BuildingGovernmentSearch16 = 0xF03DB, + BuildingGovernmentSearch20 = 0xF03DC, + BuildingGovernmentSearch24 = 0xF03DD, + BuildingGovernmentSearch32 = 0xF03DE, + CalendarRecord16 = 0xF03DF, + CalendarRecord20 = 0xF03E0, + CalendarRecord24 = 0xF03E1, + CalendarRecord28 = 0xF03E2, + CalendarRecord32 = 0xF03E3, + CalendarRecord48 = 0xF03E4, + Clipboard28 = 0xF03E5, + ClipboardMathFormula16 = 0xF03E6, + ClipboardMathFormula20 = 0xF03E7, + ClipboardMathFormula24 = 0xF03E8, + ClipboardMathFormula28 = 0xF03E9, + ClipboardMathFormula32 = 0xF03EA, + ClipboardNumber12316 = 0xF03EB, + ClipboardNumber12320 = 0xF03EC, + ClipboardNumber12324 = 0xF03ED, + ClipboardNumber12328 = 0xF03EE, + ClipboardNumber12332 = 0xF03EF, + Collections16 = 0xF03F0, + CommunicationShield16 = 0xF03F1, + CommunicationShield20 = 0xF03F2, + CommunicationShield24 = 0xF03F3, + DialpadQuestionMark20 = 0xF03F4, + DialpadQuestionMark24 = 0xF03F5, + DocumentBriefcase16 = 0xF03F6, + DocumentBriefcase32 = 0xF03F7, + DocumentSearch32 = 0xF03F8, + Fingerprint16 = 0xF03F9, + Fingerprint32 = 0xF03FA, + FolderPerson24 = 0xF03FB, + FolderPerson28 = 0xF03FC, + FolderPerson32 = 0xF03FD, + FolderPerson48 = 0xF03FE, + HatGraduationAdd16 = 0xF03FF, + HatGraduationAdd20 = 0xF0400, + HatGraduationAdd24 = 0xF0401, + LayerDiagonalAdd20 = 0xF0402, + Library32 = 0xF0403, + LightbulbFilament32 = 0xF0404, + LinkAdd16 = 0xF0405, + LinkAdd20 = 0xF0406, + LockShield16 = 0xF0407, + LockShield28 = 0xF0408, + LockShield32 = 0xF0409, + PersonVoice16 = 0xF040A, + PersonWarning16 = 0xF040B, + PersonWarning20 = 0xF040C, + PersonWarning24 = 0xF040D, + PersonWarning28 = 0xF040E, + PersonWarning32 = 0xF040F, + PersonWarning48 = 0xF0410, + ScanTypeOff24 = 0xF0411, + Screenshot16 = 0xF0412, + ScreenshotRecord16 = 0xF0413, + ScreenshotRecord20 = 0xF0414, + ScreenshotRecord24 = 0xF0415, + SlideSearch16 = 0xF0416, + SlideSearch32 = 0xF0417, + VehicleSubwayClock16 = 0xF0418, + VehicleSubwayClock20 = 0xF0419, + VehicleSubwayClock24 = 0xF041A, + VideoClipOptimize16 = 0xF041B, + VideoClipOptimize20 = 0xF041C, + VideoClipOptimize24 = 0xF041D, + VideoClipOptimize28 = 0xF041E, + VideoPersonPulse16 = 0xF041F, + VideoPersonPulse20 = 0xF0420, + VideoPersonPulse24 = 0xF0421, + VideoPersonPulse28 = 0xF0422, + ArchiveSettings32 = 0xF0423, + ArrowForward32 = 0xF0424, + ArrowReply32 = 0xF0425, + ArrowReplyAll32 = 0xF0426, + Attach32 = 0xF0427, + Autocorrect32 = 0xF0428, + Broom32 = 0xF0429, + CalendarNote16 = 0xF042A, + CalendarNote20 = 0xF042B, + CalendarNote24 = 0xF042C, + CalendarNote32 = 0xF042D, + CheckmarkUnderlineCircle24 = 0xF042E, + DataBarVerticalAscending20 = 0xF042F, + DataBarVerticalAscending24 = 0xF0430, + Diversity16 = 0xF0431, + Filter32 = 0xF0432, + FolderMail32 = 0xF0433, + GlanceHorizontal32 = 0xF0434, + GlanceHorizontalSparkle32 = 0xF0435, + GlobeArrowUp16 = 0xF0436, + GlobeArrowUp20 = 0xF0437, + GlobeArrowUp24 = 0xF0438, + GlobeError16 = 0xF0439, + GlobeError20 = 0xF043A, + GlobeError24 = 0xF043B, + GlobeProhibited16 = 0xF043C, + GlobeProhibited24 = 0xF043D, + GlobeSync16 = 0xF043E, + GlobeSync20 = 0xF043F, + GlobeSync24 = 0xF0440, + GlobeWarning16 = 0xF0441, + GlobeWarning20 = 0xF0442, + GlobeWarning24 = 0xF0443, + Important32 = 0xF0444, + LayerDiagonal16 = 0xF0445, + LayerDiagonalPerson16 = 0xF0446, + MailMultiple32 = 0xF0447, + MailRead32 = 0xF0448, + MailUnread32 = 0xF0449, + Mailbox16 = 0xF044A, + Mailbox20 = 0xF044B, + OrganizationHorizontal16 = 0xF044C, + OrganizationHorizontal24 = 0xF044D, + PeopleList32 = 0xF044E, + PersonAdd32 = 0xF044F, + PersonSquare16 = 0xF0450, + PersonSquare32 = 0xF0451, + PersonSquareCheckmark16 = 0xF0452, + PersonSquareCheckmark20 = 0xF0453, + PersonSquareCheckmark24 = 0xF0454, + PersonSquareCheckmark32 = 0xF0455, + PhoneFooterArrowDown20 = 0xF0456, + PhoneFooterArrowDown24 = 0xF0457, + PhoneHeaderArrowUp20 = 0xF0458, + PhoneHeaderArrowUp24 = 0xF0459, + Poll32 = 0xF045A, + Question32 = 0xF045B, + Screenshot28 = 0xF045C, + ScreenshotRecord28 = 0xF045D, + Star32 = 0xF045E, + TextDensity32 = 0xF045F, + TextEditStyleCharacterA32 = 0xF0460, + WrenchScrewdriver32 = 0xF0461, + ArrowClockwiseDashes16 = 0xF0462, + ArrowClockwiseDashes32 = 0xF0463, + BuildingSwap16 = 0xF0464, + BuildingSwap20 = 0xF0465, + BuildingSwap24 = 0xF0466, + BuildingSwap32 = 0xF0467, + BuildingSwap48 = 0xF0468, + Certificate32 = 0xF0469, + ClipboardBrush16 = 0xF046A, + ClipboardBrush20 = 0xF046B, + ClipboardBrush24 = 0xF046C, + ClipboardBrush28 = 0xF046D, + ClipboardBrush32 = 0xF046E, + CloudBeaker16 = 0xF046F, + CloudBeaker20 = 0xF0470, + CloudBeaker24 = 0xF0471, + CloudBeaker28 = 0xF0472, + CloudBeaker32 = 0xF0473, + CloudBeaker48 = 0xF0474, + CloudCube16 = 0xF0475, + CloudCube20 = 0xF0476, + CloudCube24 = 0xF0477, + CloudCube28 = 0xF0478, + CloudCube32 = 0xF0479, + CloudCube48 = 0xF047A, + ContractUpRight16 = 0xF047B, + ContractUpRight20 = 0xF047C, + ContractUpRight24 = 0xF047D, + ContractUpRight28 = 0xF047E, + ContractUpRight32 = 0xF047F, + ContractUpRight48 = 0xF0480, + DocumentDataLock16 = 0xF0481, + DocumentDataLock20 = 0xF0482, + DocumentDataLock24 = 0xF0483, + DocumentDataLock32 = 0xF0484, + GlanceHorizontalSparkles20 = 0xF0485, + LayoutCellFour16 = 0xF0486, + LayoutCellFour20 = 0xF0487, + LayoutCellFour24 = 0xF0488, + LayoutColumnFour16 = 0xF0489, + LayoutColumnFour20 = 0xF048A, + LayoutColumnFour24 = 0xF048B, + LayoutColumnOneThirdLeft16 = 0xF048C, + LayoutColumnOneThirdLeft20 = 0xF048D, + LayoutColumnOneThirdLeft24 = 0xF048E, + LayoutColumnOneThirdRight16 = 0xF048F, + LayoutColumnOneThirdRight20 = 0xF0490, + LayoutColumnOneThirdRight24 = 0xF0491, + LayoutColumnOneThirdRightHint16 = 0xF0492, + LayoutColumnOneThirdRightHint20 = 0xF0493, + LayoutColumnOneThirdRightHint24 = 0xF0494, + LayoutColumnThree16 = 0xF0495, + LayoutColumnThree20 = 0xF0496, + LayoutColumnThree24 = 0xF0497, + LayoutColumnTwo16 = 0xF0498, + LayoutColumnTwo20 = 0xF0499, + LayoutColumnTwo24 = 0xF049A, + LayoutColumnTwoSplitLeft16 = 0xF049B, + LayoutColumnTwoSplitLeft20 = 0xF049C, + LayoutColumnTwoSplitLeft24 = 0xF049D, + LayoutColumnTwoSplitRight16 = 0xF049E, + LayoutColumnTwoSplitRight20 = 0xF049F, + LayoutColumnTwoSplitRight24 = 0xF04A0, + LayoutRowFour16 = 0xF04A1, + LayoutRowFour20 = 0xF04A2, + LayoutRowFour24 = 0xF04A3, + LayoutRowThree16 = 0xF04A4, + LayoutRowThree20 = 0xF04A5, + LayoutRowThree24 = 0xF04A6, + LayoutRowTwo16 = 0xF04A7, + LayoutRowTwo20 = 0xF04A8, + LayoutRowTwo24 = 0xF04A9, + LayoutRowTwoSplitBottom16 = 0xF04AA, + LayoutRowTwoSplitBottom20 = 0xF04AB, + LayoutRowTwoSplitBottom24 = 0xF04AC, + LayoutRowTwoSplitTop16 = 0xF04AD, + LayoutRowTwoSplitTop20 = 0xF04AE, + LayoutRowTwoSplitTop24 = 0xF04AF, + LocationTargetSquare16 = 0xF04B0, + LocationTargetSquare20 = 0xF04B1, + LocationTargetSquare24 = 0xF04B2, + LocationTargetSquare32 = 0xF04B3, + Resize16 = 0xF04B4, + Resize28 = 0xF04B5, + Resize32 = 0xF04B6, + Resize48 = 0xF04B7, + SelectAllOff16 = 0xF04B8, + SelectAllOn16 = 0xF04B9, + ShareAndroid16 = 0xF04BA, + ShareAndroid32 = 0xF04BB, + TextArrowDownRightColumn16 = 0xF04BC, + TextArrowDownRightColumn20 = 0xF04BD, + TextArrowDownRightColumn24 = 0xF04BE, + TextArrowDownRightColumn28 = 0xF04BF, + TextArrowDownRightColumn32 = 0xF04C0, + TextArrowDownRightColumn48 = 0xF04C1, + TextEffectsSparkle20 = 0xF04C2, + TextEffectsSparkle24 = 0xF04C3, + Whiteboard16 = 0xF04C4, + WhiteboardOff16 = 0xF04C5, + WhiteboardOff20 = 0xF04C6, + WhiteboardOff24 = 0xF04C7, + Flowchart16 = 0xF04C8, + Flowchart32 = 0xF04C9, + LayerDiagonal24 = 0xF04CA, + LayerDiagonalPerson24 = 0xF04CB, + PollOff16 = 0xF04CC, + PollOff20 = 0xF04CD, + PollOff24 = 0xF04CE, + PollOff32 = 0xF04CF, + RectangleLandscapeSparkle48 = 0xF04D0, + RectangleLandscapeSync16 = 0xF04D1, + RectangleLandscapeSync20 = 0xF04D2, + RectangleLandscapeSync24 = 0xF04D3, + RectangleLandscapeSync28 = 0xF04D4, + RectangleLandscapeSyncOff16 = 0xF04D5, + RectangleLandscapeSyncOff20 = 0xF04D6, + RectangleLandscapeSyncOff24 = 0xF04D7, + RectangleLandscapeSyncOff28 = 0xF04D8, + Seat16 = 0xF04D9, + Seat20 = 0xF04DA, + Seat24 = 0xF04DB, + SeatAdd16 = 0xF04DC, + SeatAdd20 = 0xF04DD, + SeatAdd24 = 0xF04DE, + SpeakerBox16 = 0xF04DF, + SpeakerBox20 = 0xF04E0, + SpeakerBox24 = 0xF04E1, + TextEditStyleCharacterGa32 = 0xF04E2, + WindowAd24 = 0xF04E3, + WrenchSettings20 = 0xF04E4, + WrenchSettings24 = 0xF04E5, + BuildingLighthouse24 = 0xF04E6, + BuildingLighthouse32 = 0xF04E7, + BuildingLighthouse48 = 0xF04E8, + CalendarLink24 = 0xF04E9, + CalendarLink28 = 0xF04EA, + CalendarVideo24 = 0xF04EB, + CalendarVideo28 = 0xF04EC, + Cookies16 = 0xF04ED, + Cookies28 = 0xF04EE, + Cookies32 = 0xF04EF, + Cookies48 = 0xF04F0, + HardDrive28 = 0xF04F1, + HardDrive48 = 0xF04F2, + Laptop32 = 0xF04F3, + LaptopSettings20 = 0xF04F4, + LaptopSettings24 = 0xF04F5, + LaptopSettings32 = 0xF04F6, + PeopleAudience32 = 0xF04F7, + ShoppingBagAdd20 = 0xF04F8, + ShoppingBagAdd24 = 0xF04F9, + StreetSign20 = 0xF04FA, + StreetSign24 = 0xF04FB, + VideoLink24 = 0xF04FC, + VideoLink28 = 0xF04FD, + BuildingLighthouse16 = 0xF04FE, + CalendarSparkle16 = 0xF04FF, + CalendarSparkle20 = 0xF0500, + CalendarSparkle24 = 0xF0501, + CalendarSparkle28 = 0xF0502, + CalendarSparkle32 = 0xF0503, + CalendarSparkle48 = 0xF0504, + CalendarTemplate20 = 0xF0505, + CalendarTemplate24 = 0xF0506, + CalendarTemplate32 = 0xF0507, + Clipboard12 = 0xF0508, + Clipboard48 = 0xF0509, + Compose12 = 0xF050A, + Compose32 = 0xF050B, + Compose48 = 0xF050C, + Globe28 = 0xF050D, + Guest12 = 0xF050E, + Guest32 = 0xF050F, + Guest48 = 0xF0510, + LaptopBriefcase20 = 0xF0511, + LaptopBriefcase24 = 0xF0512, + LaptopBriefcase32 = 0xF0513, + LayerDiagonalSparkle16 = 0xF0514, + LayerDiagonalSparkle20 = 0xF0515, + LayerDiagonalSparkle24 = 0xF0516, + PaymentWireless16 = 0xF0517, + PaymentWireless20 = 0xF0518, + PaymentWireless24 = 0xF0519, + PaymentWireless28 = 0xF051A, + PaymentWireless32 = 0xF051B, + PaymentWireless48 = 0xF051C, + Status28 = 0xF051D, + Status32 = 0xF051E, + Status48 = 0xF051F, + VideoOff16 = 0xF0520, + CheckmarkCircleWarning16 = 0xF0521, + CheckmarkCircleWarning20 = 0xF0522, + CheckmarkCircleWarning24 = 0xF0523, + CloudArrowRight16 = 0xF0524, + CloudArrowRight20 = 0xF0525, + CloudArrowRight24 = 0xF0526, + DocumentArrowDown24 = 0xF0527, + DocumentSignature16 = 0xF0528, + DocumentSignature20 = 0xF0529, + DocumentSignature24 = 0xF052A, + DocumentSignature28 = 0xF052B, + DocumentSignature32 = 0xF052C, + DocumentSignature48 = 0xF052D, + HomeGarage20 = 0xF052E, + HomeGarage24 = 0xF052F, + ImageSplit20 = 0xF0530, + ImageSplit24 = 0xF0531, + Laptop48 = 0xF0532, + LineFlowDiagonalUpRight16 = 0xF0533, + LineFlowDiagonalUpRight20 = 0xF0534, + LineFlowDiagonalUpRight24 = 0xF0535, + LineFlowDiagonalUpRight32 = 0xF0536, + MailArrowClockwise16 = 0xF0537, + MailArrowClockwise20 = 0xF0538, + MailArrowClockwise24 = 0xF0539, + PersonPasskey16 = 0xF053A, + PersonPasskey20 = 0xF053B, + PersonPasskey24 = 0xF053C, + PersonPasskey28 = 0xF053D, + PersonPasskey32 = 0xF053E, + PersonPasskey48 = 0xF053F, + PersonProhibited32 = 0xF0540, + PersonRibbon24 = 0xF0541, + PlantCattail20 = 0xF0542, + PlantCattail24 = 0xF0543, + Storage16 = 0xF0544, + Storage28 = 0xF0545, + Storage32 = 0xF0546, + Storage48 = 0xF0547, + VideoClipWand16 = 0xF0548, + VideoClipWand20 = 0xF0549, + VideoClipWand24 = 0xF054A, + WindowFingerprint16 = 0xF054B, + WindowFingerprint20 = 0xF054C, + WindowFingerprint24 = 0xF054D, + WindowFingerprint28 = 0xF054E, + WindowFingerprint32 = 0xF054F, + WindowFingerprint48 = 0xF0550, + AccessibilityError20 = 0xF0551, + AccessibilityError24 = 0xF0552, + AccessibilityQuestionMark20 = 0xF0553, + AccessibilityQuestionMark24 = 0xF0554, + ArrowDownExclamation24 = 0xF0555, + ArrowSortUpLines16 = 0xF0556, + ArrowSortUpLines20 = 0xF0557, + ArrowSortUpLines24 = 0xF0558, + ArrowUpExclamation16 = 0xF0559, + ArrowUpExclamation20 = 0xF055A, + ArrowUpExclamation24 = 0xF055B, + Bench20 = 0xF055C, + Bench24 = 0xF055D, + BuildingLighthouse28 = 0xF055E, + CalendarVideo20 = 0xF055F, + ClockBill16 = 0xF0560, + ClockBill20 = 0xF0561, + ClockBill24 = 0xF0562, + ClockBill32 = 0xF0563, + DataUsage16 = 0xF0564, + DataUsageSettings16 = 0xF0565, + DataUsageSettings24 = 0xF0566, + EditPerson20 = 0xF0567, + EditPerson24 = 0xF0568, + Highway20 = 0xF0569, + Highway24 = 0xF056A, + LaptopPerson20 = 0xF056B, + LaptopPerson24 = 0xF056C, + LaptopPerson48 = 0xF056D, + LocationRipple16 = 0xF056E, + LocationRipple20 = 0xF056F, + LocationRipple24 = 0xF0570, + MailArrowDoubleBack32 = 0xF0571, + MailBriefcase48 = 0xF0572, + Options28 = 0xF0573, + Options32 = 0xF0574, + PeopleAdd32 = 0xF0575, + PersonAlert32 = 0xF0576, + Road20 = 0xF0577, + Road24 = 0xF0578, + Save32 = 0xF0579, + TabDesktopMultiple24 = 0xF057A, + TabDesktopMultipleSparkle16 = 0xF057B, + TabDesktopMultipleSparkle20 = 0xF057C, + TabDesktopMultipleSparkle24 = 0xF057D, + VehicleTractor20 = 0xF057E, + VehicleTractor24 = 0xF057F, + Classification32 = 0xF0580, + DocumentTarget20 = 0xF0581, + DocumentTarget24 = 0xF0582, + DocumentTarget32 = 0xF0583, + EmojiMeme16 = 0xF0584, + EmojiMeme20 = 0xF0585, + EmojiMeme24 = 0xF0586, + HandPoint16 = 0xF0587, + HandPoint20 = 0xF0588, + HandPoint24 = 0xF0589, + HandPoint28 = 0xF058A, + HandPoint32 = 0xF058B, + HandPoint48 = 0xF058C, + MailReadBriefcase48 = 0xF058D, + PeopleSubtract20 = 0xF058E, + PeopleSubtract24 = 0xF058F, + PeopleSubtract32 = 0xF0590, + PersonAlertOff16 = 0xF0591, + PersonAlertOff20 = 0xF0592, + PersonAlertOff24 = 0xF0593, + PersonAlertOff32 = 0xF0594, + ShoppingBagAdd16 = 0xF0595, + SpatulaSpoon16 = 0xF0596, + SpatulaSpoon20 = 0xF0597, + SpatulaSpoon24 = 0xF0598, + SpatulaSpoon28 = 0xF0599, + SpatulaSpoon32 = 0xF059A, + SpatulaSpoon48 = 0xF059B, } - -#pragma warning restore CS1591 diff --git a/source/RevitLookup.UI/Controls/TextBlock/TextBlock.cs b/source/RevitLookup.UI/Controls/TextBlock/TextBlock.cs index 86c6a2fd0..2a4cc2b98 100644 --- a/source/RevitLookup.UI/Controls/TextBlock/TextBlock.cs +++ b/source/RevitLookup.UI/Controls/TextBlock/TextBlock.cs @@ -3,9 +3,6 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -using System.Windows.Documents; -using Wpf.Ui.Extensions; - // ReSharper disable once CheckNamespace namespace Wpf.Ui.Controls; @@ -14,34 +11,36 @@ namespace Wpf.Ui.Controls; /// public class TextBlock : System.Windows.Controls.TextBlock { - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty FontTypographyProperty = DependencyProperty.Register( nameof(FontTypography), typeof(FontTypography), typeof(TextBlock), new PropertyMetadata( FontTypography.Body, - static (o, args) => ((TextBlock)o).OnFontTypographyChanged((FontTypography)args.NewValue) + static (o, args) => + { + ((TextBlock)o).OnFontTypographyChanged((FontTypography)args.NewValue); + } ) ); - /// - /// Property for . - /// + /// Identifies the dependency property. public static readonly DependencyProperty AppearanceProperty = DependencyProperty.Register( nameof(Appearance), typeof(TextColor), typeof(TextBlock), new PropertyMetadata( TextColor.Primary, - static (o, args) => ((TextBlock)o).OnAppearanceChanged((TextColor)args.NewValue) + static (o, args) => + { + ((TextBlock)o).OnAppearanceChanged((TextColor)args.NewValue); + } ) ); /// - /// TODO + /// Gets or sets the of the text. /// public FontTypography FontTypography { @@ -50,7 +49,7 @@ public FontTypography FontTypography } /// - /// TODO + /// Gets or sets the color of the text. /// public TextColor Appearance { diff --git a/source/RevitLookup.UI/Controls/TextBlock/TextBlock.xaml b/source/RevitLookup.UI/Controls/TextBlock/TextBlock.xaml index 3212231c6..d07d15bda 100644 --- a/source/RevitLookup.UI/Controls/TextBlock/TextBlock.xaml +++ b/source/RevitLookup.UI/Controls/TextBlock/TextBlock.xaml @@ -9,12 +9,12 @@ - + + \ No newline at end of file diff --git a/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Filled.ttf b/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Filled.ttf index 8726d355c..21e767087 100644 Binary files a/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Filled.ttf and b/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Filled.ttf differ diff --git a/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Regular.ttf b/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Regular.ttf index a885f35b4..ff12b0654 100644 Binary files a/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Regular.ttf and b/source/RevitLookup.UI/Resources/Fonts/FluentSystemIcons-Regular.ttf differ diff --git a/source/RevitLookup.UI/Resources/Theme/Dark.xaml b/source/RevitLookup.UI/Resources/Theme/Dark.xaml index f15263e42..5a8200d85 100644 --- a/source/RevitLookup.UI/Resources/Theme/Dark.xaml +++ b/source/RevitLookup.UI/Resources/Theme/Dark.xaml @@ -267,13 +267,10 @@ - - - - + - - + + @@ -319,9 +316,8 @@ - - + @@ -487,7 +483,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Theme/HC1.xaml b/source/RevitLookup.UI/Resources/Theme/HC1.xaml index fc241b194..06493c04f 100644 --- a/source/RevitLookup.UI/Resources/Theme/HC1.xaml +++ b/source/RevitLookup.UI/Resources/Theme/HC1.xaml @@ -133,18 +133,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -204,7 +204,6 @@ - @@ -375,7 +374,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Theme/HC2.xaml b/source/RevitLookup.UI/Resources/Theme/HC2.xaml index af54fb4b9..dd9bf09bb 100644 --- a/source/RevitLookup.UI/Resources/Theme/HC2.xaml +++ b/source/RevitLookup.UI/Resources/Theme/HC2.xaml @@ -132,18 +132,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -203,7 +203,6 @@ - @@ -374,7 +373,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Theme/HCBlack.xaml b/source/RevitLookup.UI/Resources/Theme/HCBlack.xaml index 8f320bb7d..f1c98689e 100644 --- a/source/RevitLookup.UI/Resources/Theme/HCBlack.xaml +++ b/source/RevitLookup.UI/Resources/Theme/HCBlack.xaml @@ -132,18 +132,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -203,7 +203,6 @@ - @@ -374,7 +373,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Theme/HCWhite.xaml b/source/RevitLookup.UI/Resources/Theme/HCWhite.xaml index a25854bf0..60ef60dd7 100644 --- a/source/RevitLookup.UI/Resources/Theme/HCWhite.xaml +++ b/source/RevitLookup.UI/Resources/Theme/HCWhite.xaml @@ -132,18 +132,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + @@ -203,7 +203,6 @@ - @@ -374,7 +373,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Theme/Light.xaml b/source/RevitLookup.UI/Resources/Theme/Light.xaml index ee874abfc..65af60613 100644 --- a/source/RevitLookup.UI/Resources/Theme/Light.xaml +++ b/source/RevitLookup.UI/Resources/Theme/Light.xaml @@ -260,7 +260,7 @@ - + @@ -268,13 +268,10 @@ - - - - + - - + + @@ -320,9 +317,8 @@ - - + @@ -488,7 +484,7 @@ - + diff --git a/source/RevitLookup.UI/Resources/Typography.xaml b/source/RevitLookup.UI/Resources/Typography.xaml index f32cf17eb..14ac44a95 100644 --- a/source/RevitLookup.UI/Resources/Typography.xaml +++ b/source/RevitLookup.UI/Resources/Typography.xaml @@ -3,7 +3,6 @@ diff --git a/source/RevitLookup.UI/Resources/Wpf.Ui.xaml b/source/RevitLookup.UI/Resources/Wpf.Ui.xaml index 4ed078f8a..362815349 100644 --- a/source/RevitLookup.UI/Resources/Wpf.Ui.xaml +++ b/source/RevitLookup.UI/Resources/Wpf.Ui.xaml @@ -14,7 +14,9 @@ + + @@ -33,7 +35,7 @@ - + @@ -43,6 +45,7 @@ + @@ -56,6 +59,7 @@ + diff --git a/source/RevitLookup.UI/RevitLookup.UI.csproj b/source/RevitLookup.UI/RevitLookup.UI.csproj index 4f07590c0..f6c0f25fa 100644 --- a/source/RevitLookup.UI/RevitLookup.UI.csproj +++ b/source/RevitLookup.UI/RevitLookup.UI.csproj @@ -1,30 +1,11 @@ - + true - latest - x64 - true - net48;net8.0-windows true - enable - CS8603;CS8618;CS8629;CS8600;CS0414;CS4014;CS8604;CS8765;CS8602;CS0168 - - - + net48;net8.0-windows + CS0108;CS8601;CS4014;CS8602 Wpf.Ui - true - - - - true - full - $(DefineConstants);DEBUG - - - true - none - $(DefineConstants);RELEASE @@ -33,10 +14,7 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + \ No newline at end of file diff --git a/source/RevitLookup.UI/SimpleContentDialogCreateOptions.cs b/source/RevitLookup.UI/SimpleContentDialogCreateOptions.cs index 35a3f7ed4..7715f9e42 100644 --- a/source/RevitLookup.UI/SimpleContentDialogCreateOptions.cs +++ b/source/RevitLookup.UI/SimpleContentDialogCreateOptions.cs @@ -36,4 +36,4 @@ public class SimpleContentDialogCreateOptions /// If not added, or , it will not be displayed. /// public string SecondaryButtonText { get; set; } = string.Empty; -} \ No newline at end of file +} diff --git a/source/RevitLookup.UI/SnackbarService.cs b/source/RevitLookup.UI/SnackbarService.cs index e6336079f..377745f9e 100644 --- a/source/RevitLookup.UI/SnackbarService.cs +++ b/source/RevitLookup.UI/SnackbarService.cs @@ -26,13 +26,8 @@ public void SetSnackbarPresenter(SnackbarPresenter contentPresenter) } /// - public SnackbarPresenter GetSnackbarPresenter() + public SnackbarPresenter? GetSnackbarPresenter() { - if (_presenter is null) - { - throw new ArgumentNullException($"The SnackbarPresenter didn't set previously."); - } - return _presenter; } @@ -47,7 +42,7 @@ TimeSpan timeout { if (_presenter is null) { - throw new ArgumentNullException($"The SnackbarPresenter didn't set previously."); + throw new InvalidOperationException($"The SnackbarPresenter was never set"); } _snackbar ??= new Snackbar(_presenter); diff --git a/source/RevitLookup.UI/TaskBarService.cs b/source/RevitLookup.UI/TaskBarService.cs index 2fa3ed4f6..03d2df4ea 100644 --- a/source/RevitLookup.UI/TaskBarService.cs +++ b/source/RevitLookup.UI/TaskBarService.cs @@ -12,7 +12,7 @@ namespace Wpf.Ui; /// public partial class TaskBarService : ITaskBarService { - private readonly Dictionary _progressStates = new(); + private readonly Dictionary _progressStates = []; /// public virtual TaskBarProgressState GetState(IntPtr hWnd) @@ -33,7 +33,7 @@ public virtual TaskBarProgressState GetState(Window? window) return TaskBarProgressState.None; } - var windowHandle = new WindowInteropHelper(window).Handle; + IntPtr windowHandle = new WindowInteropHelper(window).Handle; if (!_progressStates.TryGetValue(windowHandle, out TaskBarProgressState progressState)) { @@ -78,7 +78,7 @@ public virtual bool SetValue(Window? window, int current, int total) return false; } - var windowHandle = new WindowInteropHelper(window).Handle; + IntPtr windowHandle = new WindowInteropHelper(window).Handle; if (!_progressStates.TryGetValue(windowHandle, out TaskBarProgressState progressState)) { @@ -108,7 +108,7 @@ int total /// public virtual bool SetValue(IntPtr hWnd, int current, int total) { - if (!_progressStates.TryGetValue(hWnd, out var progressState)) + if (!_progressStates.TryGetValue(hWnd, out TaskBarProgressState progressState)) { return TaskBarProgress.SetValue(hWnd, TaskBarProgressState.Normal, current, total); } diff --git a/source/RevitLookup.UI/ThemeService.cs b/source/RevitLookup.UI/ThemeService.cs index a6b5a1a8a..713cc9440 100644 --- a/source/RevitLookup.UI/ThemeService.cs +++ b/source/RevitLookup.UI/ThemeService.cs @@ -72,7 +72,7 @@ public bool SetAccent(Color accentColor) public bool SetAccent(SolidColorBrush accentSolidBrush) { Color color = accentSolidBrush.Color; - color.A = (byte)Math.Round(accentSolidBrush.Opacity * Byte.MaxValue); + color.A = (byte)Math.Round(accentSolidBrush.Opacity * byte.MaxValue); ApplicationAccentColorManager.Apply(color); diff --git a/source/RevitLookup.UI/UiApplication.cs b/source/RevitLookup.UI/UiApplication.cs new file mode 100644 index 000000000..25aa4b4b5 --- /dev/null +++ b/source/RevitLookup.UI/UiApplication.cs @@ -0,0 +1,138 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui; + +/// +/// Represents a UI application. +/// +public class UiApplication +{ + private static UiApplication? _uiApplication; + + private readonly Application? _application; + + private ResourceDictionary? _resources; + + private Window? _mainWindow; + + /// + /// Initializes a new instance of the class. + /// + public UiApplication(Application application) + { + if (application is null) + { + return; + } + + if (!ApplicationHasResources(application)) + { + return; + } + + _application = application; + + System.Diagnostics.Debug.WriteLine( + $"INFO | {typeof(UiApplication)} application is {_application}", + "Wpf.Ui" + ); + } + + /// + /// Gets a value indicating whether the application is running outside of the desktop app context. + /// + public bool IsApplication => _application is not null; + + /// + /// Gets the current application. + /// + public static UiApplication Current + { + get + { + _uiApplication ??= new UiApplication(Application.Current); + + return _uiApplication; + } + } + + /// + /// Gets or sets the application's main window. + /// + public Window? MainWindow + { + get => _application?.MainWindow ?? _mainWindow; + set + { + if (_application != null) + { + _application.MainWindow = value; + } + + _mainWindow = value; + } + } + + /// + /// Gets or sets the application's resources. + /// + public ResourceDictionary Resources + { + get + { + if (_resources is null) + { + _resources = []; + + try + { + Wpf.Ui.Appearance.ApplicationAccentColorManager.ApplySystemAccent(); + var themesDictionary = new Markup.ThemesDictionary(); + var controlsDictionary = new Markup.ControlsDictionary(); + _resources.MergedDictionaries.Add(themesDictionary); + _resources.MergedDictionaries.Add(controlsDictionary); + } + catch { } + } + + return _application?.Resources ?? _resources; + } + set + { + if (_application is not null) + { + _application.Resources = value; + } + + _resources = value; + } + } + + /// + /// Gets or sets the application's main window. + /// + public object TryFindResource(object resourceKey) + { + return Resources[resourceKey]; + } + + /// + /// Turns the application's into shutdown mode. + /// + public void Shutdown() + { + _application?.Shutdown(); + } + + private static bool ApplicationHasResources(Application application) + { + return application + .Resources.MergedDictionaries.Where(e => e.Source is not null) + .Any(e => + e.Source.ToString().Contains(Appearance.ApplicationThemeManager.LibraryNamespace, StringComparison.OrdinalIgnoreCase) + ); + } +} diff --git a/source/RevitLookup.UI/VisualStudioToolsManifest.xml b/source/RevitLookup.UI/VisualStudioToolsManifest.xml index ed61cc8c5..7444460fc 100644 --- a/source/RevitLookup.UI/VisualStudioToolsManifest.xml +++ b/source/RevitLookup.UI/VisualStudioToolsManifest.xml @@ -27,6 +27,7 @@ + diff --git a/source/RevitLookup.UI/Win32/Utilities.cs b/source/RevitLookup.UI/Win32/Utilities.cs index 274b93067..97e32c27f 100644 --- a/source/RevitLookup.UI/Win32/Utilities.cs +++ b/source/RevitLookup.UI/Win32/Utilities.cs @@ -16,10 +16,17 @@ namespace Wpf.Ui.Win32; /// // ReSharper disable InconsistentNaming // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract -public class Utilities +// ReSharper disable once ClassNeverInstantiated.Global +internal sealed class Utilities { private static readonly PlatformID _osPlatform = Environment.OSVersion.Platform; + public static readonly Version Vista = new(6, 0); + + public static readonly Version Windows7 = new(6, 1); + + public static readonly Version Windows8 = new(6, 2); + private static readonly Version _osVersion = #if NET5_0_OR_GREATER Environment.OSVersion.Version; @@ -28,47 +35,47 @@ public class Utilities #endif /// - /// Whether the operating system is NT or newer. + /// Gets a value indicating whether the operating system is NT or newer. /// public static bool IsNT => _osPlatform == PlatformID.Win32NT; /// - /// Whether the operating system version is greater than or equal to 6.0. + /// Gets a value indicating whether the operating system version is greater than or equal to 6.0. /// - public static bool IsOSVistaOrNewer => _osVersion >= new Version(6, 0); + public static bool IsOSVistaOrNewer => _osVersion >= Vista; /// - /// Whether the operating system version is greater than or equal to 6.1. + /// Gets a value indicating whether the operating system version is greater than or equal to 6.1. /// - public static bool IsOSWindows7OrNewer => _osVersion >= new Version(6, 1); + public static bool IsOSWindows7OrNewer => _osVersion >= Windows7; /// - /// Whether the operating system version is greater than or equal to 6.2. + /// Gets a value indicating whether the operating system version is greater than or equal to 6.2. /// - public static bool IsOSWindows8OrNewer => _osVersion >= new Version(6, 2); + public static bool IsOSWindows8OrNewer => _osVersion >= Windows8; /// - /// Whether the operating system version is greater than or equal to 10.0* (build 10240). + /// Gets a value indicating whether the operating system version is greater than or equal to 10.0* (build 10240). /// public static bool IsOSWindows10OrNewer => _osVersion.Build >= 10240; /// - /// Whether the operating system version is greater than or equal to 10.0* (build 22000). + /// Gets a value indicating whether the operating system version is greater than or equal to 10.0* (build 22000). /// public static bool IsOSWindows11OrNewer => _osVersion.Build >= 22000; /// - /// Whether the operating system version is greater than or equal to 10.0* (build 22523). + /// Gets a value indicating whether the operating system version is greater than or equal to 10.0* (build 22523). /// public static bool IsOSWindows11Insider1OrNewer => _osVersion.Build >= 22523; /// - /// Whether the operating system version is greater than or equal to 10.0* (build 22557). + /// Gets a value indicating whether the operating system version is greater than or equal to 10.0* (build 22557). /// public static bool IsOSWindows11Insider2OrNewer => _osVersion.Build >= 22557; /// - /// Indicates whether Desktop Window Manager (DWM) composition is enabled. + /// Gets a value indicating whether Desktop Window Manager (DWM) composition is enabled. /// public static bool IsCompositionEnabled { @@ -79,7 +86,7 @@ public static bool IsCompositionEnabled return false; } - Interop.Dwmapi.DwmIsCompositionEnabled(out var pfEnabled); + _ = Interop.Dwmapi.DwmIsCompositionEnabled(out var pfEnabled); return pfEnabled != 0; } @@ -90,7 +97,7 @@ public static void SafeDispose(ref T disposable) { // Dispose can safely be called on an object multiple times. IDisposable t = disposable; - disposable = default(T); + disposable = default; if (t is null) { @@ -104,15 +111,15 @@ public static void SafeRelease(ref T comObject) where T : class { T t = comObject; - comObject = default(T); + comObject = default; if (t is null) { return; } - Debug.Assert(Marshal.IsComObject(t)); - Marshal.ReleaseComObject(t); + Debug.Assert(Marshal.IsComObject(t), "Object is not a COM object."); + _ = Marshal.ReleaseComObject(t); } #if !NET5_0_OR_GREATER @@ -137,8 +144,8 @@ out var majorObj major = (int)majorObj; } - // When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' - else if ( + else // When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' + if ( TryGetRegistryKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", @@ -146,7 +153,7 @@ out var version ) ) { - version ??= String.Empty; + version ??= string.Empty; var versionParts = ((string)version).Split('.'); @@ -169,12 +176,12 @@ out var minorObj ) ) { - minorObj ??= String.Empty; + minorObj ??= string.Empty; minor = (int)minorObj; } - // When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' - else if ( + else // When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' + if ( TryGetRegistryKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", @@ -182,12 +189,14 @@ out var version ) ) { - version ??= String.Empty; + version ??= string.Empty; var versionParts = ((string)version).Split('.'); if (versionParts.Length >= 2) + { minor = int.TryParse(versionParts[1], out int minorAsInt) ? minorAsInt : 0; + } } } @@ -201,7 +210,7 @@ out var buildObj ) ) { - buildObj ??= String.Empty; + buildObj ??= string.Empty; build = int.TryParse((string)buildObj, out int buildAsInt) ? buildAsInt : 0; } @@ -216,7 +225,7 @@ private static bool TryGetRegistryKey(string path, string key, out object? value try { - using var rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(path); + using Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(path); if (rk == null) { diff --git a/source/RevitLookup/Application.cs b/source/RevitLookup/Application.cs index 527141c3c..8db4e8383 100644 --- a/source/RevitLookup/Application.cs +++ b/source/RevitLookup/Application.cs @@ -21,8 +21,10 @@ using System.Windows.Interop; using System.Windows.Media; using Nice3point.Revit.Toolkit.External; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Settings; using RevitLookup.Core; -using RevitLookup.Services.Contracts; +using RevitLookup.Services.Application; namespace RevitLookup; @@ -31,10 +33,13 @@ public class Application : ExternalApplication { public override void OnStartup() { - RevitShell.RegisterHandlers(); Host.Start(); + RevitShell.RegisterHandlers(); + + EnableThemes(); + EnableHardwareRendering(); - RibbonController.CreatePanel(Application); + Host.GetService().CreateRibbon(); } public override void OnShutdown() @@ -42,6 +47,12 @@ public override void OnShutdown() Host.Stop(); } + private static void EnableThemes() + { + var themeWatcherService = Host.GetService(); + themeWatcherService.Initialize(); + } + public static void EnableHardwareRendering() { var settingsService = Host.GetService(); diff --git a/source/RevitLookup/Commands/DashboardCommand.cs b/source/RevitLookup/Commands/DashboardCommand.cs index 32b652674..627b996d2 100644 --- a/source/RevitLookup/Commands/DashboardCommand.cs +++ b/source/RevitLookup/Commands/DashboardCommand.cs @@ -20,8 +20,8 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Dashboard; namespace RevitLookup.Commands; @@ -31,6 +31,7 @@ public class DashboardCommand : ExternalCommand { public override void Execute() { - Host.GetService().Show(); + Host.GetService() + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/EventMonitorCommand.cs b/source/RevitLookup/Commands/EventMonitorCommand.cs index d111bb02a..0f2290f94 100644 --- a/source/RevitLookup/Commands/EventMonitorCommand.cs +++ b/source/RevitLookup/Commands/EventMonitorCommand.cs @@ -20,8 +20,8 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -31,6 +31,7 @@ public class EventMonitorCommand : ExternalCommand { public override void Execute() { - Host.GetService().Show(); + Host.GetService() + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SearchElementsCommand.cs b/source/RevitLookup/Commands/SearchElementsCommand.cs index 2efa63aca..d259151d1 100644 --- a/source/RevitLookup/Commands/SearchElementsCommand.cs +++ b/source/RevitLookup/Commands/SearchElementsCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.ViewModels.Dashboard; +using RevitLookup.UI.Framework.Views.Dashboard; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SearchElementsCommand : ExternalCommand { public override void Execute() { - Host.GetService() + Host.GetService() .Show() - .Execute(dashboard => dashboard.OpenDialogCommand.Execute("search")); + .RunService(dashboard => dashboard.OpenDialogCommand.Execute("search")); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopDatabaseCommand.cs b/source/RevitLookup/Commands/SnoopDatabaseCommand.cs index fbfb1cdd5..62e8d51fb 100644 --- a/source/RevitLookup/Commands/SnoopDatabaseCommand.cs +++ b/source/RevitLookup/Commands/SnoopDatabaseCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopDatabaseCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Database) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Database) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopDocumentCommand.cs b/source/RevitLookup/Commands/SnoopDocumentCommand.cs index 8318c2d2b..da8bad3de 100644 --- a/source/RevitLookup/Commands/SnoopDocumentCommand.cs +++ b/source/RevitLookup/Commands/SnoopDocumentCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopDocumentCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Document) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Document) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopEdgeCommand.cs b/source/RevitLookup/Commands/SnoopEdgeCommand.cs index 26dab7757..7cabf1768 100644 --- a/source/RevitLookup/Commands/SnoopEdgeCommand.cs +++ b/source/RevitLookup/Commands/SnoopEdgeCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopEdgeCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Edge) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Edge) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopFaceCommand.cs b/source/RevitLookup/Commands/SnoopFaceCommand.cs index 9f388034c..fcd2b5208 100644 --- a/source/RevitLookup/Commands/SnoopFaceCommand.cs +++ b/source/RevitLookup/Commands/SnoopFaceCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopFaceCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Face) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Face) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopLinkedElementCommand.cs b/source/RevitLookup/Commands/SnoopLinkedElementCommand.cs index cfc625056..bd5268c56 100644 --- a/source/RevitLookup/Commands/SnoopLinkedElementCommand.cs +++ b/source/RevitLookup/Commands/SnoopLinkedElementCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopLinkedElementCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.LinkedElement) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.LinkedElement) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopPointCommand.cs b/source/RevitLookup/Commands/SnoopPointCommand.cs index 01a6bdd39..3d317b8e0 100644 --- a/source/RevitLookup/Commands/SnoopPointCommand.cs +++ b/source/RevitLookup/Commands/SnoopPointCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopPointCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Point) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Point) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopSelectionCommand.cs b/source/RevitLookup/Commands/SnoopSelectionCommand.cs index b6ac45936..12ef1aadb 100644 --- a/source/RevitLookup/Commands/SnoopSelectionCommand.cs +++ b/source/RevitLookup/Commands/SnoopSelectionCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopSelectionCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.Selection) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.Selection) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopSubElementCommand.cs b/source/RevitLookup/Commands/SnoopSubElementCommand.cs index 72999de59..256edd8f3 100644 --- a/source/RevitLookup/Commands/SnoopSubElementCommand.cs +++ b/source/RevitLookup/Commands/SnoopSubElementCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopSubElementCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.SubElement) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.SubElement) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Commands/SnoopViewCommand.cs b/source/RevitLookup/Commands/SnoopViewCommand.cs index 695ca8eac..27556d5fa 100644 --- a/source/RevitLookup/Commands/SnoopViewCommand.cs +++ b/source/RevitLookup/Commands/SnoopViewCommand.cs @@ -20,9 +20,9 @@ using Autodesk.Revit.Attributes; using Nice3point.Revit.Toolkit.External; -using RevitLookup.Services.Contracts; -using RevitLookup.Services.Enums; -using RevitLookup.Views.Pages; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.UI.Framework.Views.Decomposition; namespace RevitLookup.Commands; @@ -32,8 +32,8 @@ public class SnoopViewCommand : ExternalCommand { public override void Execute() { - Host.GetService() - .Snoop(SnoopableType.View) - .Show(); + Host.GetService() + .Decompose(KnownDecompositionObject.View) + .Show(); } } \ No newline at end of file diff --git a/source/RevitLookup/Config/ApplicationOptions.cs b/source/RevitLookup/Config/ApplicationOptions.cs new file mode 100644 index 000000000..56ae8c83e --- /dev/null +++ b/source/RevitLookup/Config/ApplicationOptions.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.Versioning; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using RevitLookup.Abstractions.Options; +using RevitLookup.Common.Utils; + +namespace RevitLookup.Config; + +public static class ApplicationOptions +{ + public static void AddApplicationOptions(this IServiceCollection services) + { + services.Configure(options => options.SuppressStatusMessages = true); + } + + public static void AddFolderOptions(this IServiceCollection services) + { + var rootPath = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName; + services.Configure(options => + { + options.RootFolder = rootPath; + options.ConfigFolder = Path.Combine(rootPath, "Config"); + options.DownloadsFolder = Path.Combine(rootPath, "Downloads"); + options.GeneralSettingsPath = Path.Combine(rootPath, "Config", "Settings.cfg"); + options.RenderSettingsPath = Path.Combine(rootPath, "Config", "RenderSettings.cfg"); + }); + } + + public static void AddAssemblyOptions(this IServiceCollection services) + { + var assembly = Assembly.GetExecutingAssembly(); + var assemblyLocation = assembly.Location; + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); + var fileVersion = new Version(FileVersionInfo.GetVersionInfo(assemblyLocation).FileVersion!); + + var targetFrameworkAttribute = assembly.GetCustomAttributes(typeof(TargetFrameworkAttribute), true) + .Cast() + .First(); + + services.Configure(options => + { + options.Framework = targetFrameworkAttribute.FrameworkDisplayName ?? targetFrameworkAttribute.FrameworkName; + options.Version = new Version(fileVersion.Major, fileVersion.Minor, fileVersion.Build); + options.HasAdminAccess = assemblyLocation.StartsWith(appDataPath) || !AccessUtils.CheckWriteAccess(assemblyLocation); + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Config/LoggerConfigurator.cs b/source/RevitLookup/Config/LoggerConfigurator.cs index b0f8edcb0..0f7b19af3 100644 --- a/source/RevitLookup/Config/LoggerConfigurator.cs +++ b/source/RevitLookup/Config/LoggerConfigurator.cs @@ -8,15 +8,15 @@ namespace RevitLookup.Config; public static class LoggerConfigurator { private const string LogTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"; - + public static void AddSerilogConfiguration(this ILoggingBuilder builder) { var logger = CreateDefaultLogger(); builder.AddSerilog(logger); - + AppDomain.CurrentDomain.UnhandledException += OnOnUnhandledException; } - + private static Logger CreateDefaultLogger() { return new LoggerConfiguration() @@ -26,7 +26,7 @@ private static Logger CreateDefaultLogger() .MinimumLevel.Debug() .CreateLogger(); } - + private static void OnOnUnhandledException(object sender, UnhandledExceptionEventArgs args) { var exception = (Exception) args.ExceptionObject; diff --git a/source/RevitLookup/Config/SerializerOptions.cs b/source/RevitLookup/Config/SerializerOptions.cs new file mode 100644 index 000000000..01f2853c2 --- /dev/null +++ b/source/RevitLookup/Config/SerializerOptions.cs @@ -0,0 +1,23 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.Extensions.DependencyInjection; + +namespace RevitLookup.Config; + +public static class SerializerOptions +{ + /// + /// Add global JsonSerialization configuration/> + /// + public static void AddSerializerOptions(this IServiceCollection services) + { + services.Configure(options => + { +#if DEBUG + options.WriteIndented = true; +#endif + options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + options.Converters.Add(new JsonStringEnumConverter()); + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/ContextFinder.cs b/source/RevitLookup/Core/Decomposition/ContextFinder.cs new file mode 100644 index 000000000..1519ed8f0 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/ContextFinder.cs @@ -0,0 +1,58 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +namespace RevitLookup.Core.Decomposition; + +public static class ContextFinder +{ + public static Document FindRevitContext(object obj) + { + var context = GetKnownContext(obj); + if (context is not null) return context; + + context = Context.ActiveDocument; + if (context is null) + { + throw new InvalidOperationException("RevitLookup executing in the invalid context"); + } + + return context; + } + + public static Document FindRevitContext(object obj, Document context) + { + var actualContext = GetKnownContext(obj); + + if (actualContext is null) return context; + if (!actualContext.Equals(context)) return actualContext; + return context; + } + + private static Document? GetKnownContext(object obj) + { + return obj switch + { + Element element => element.Document, + Parameter {Element: not null} parameter => parameter.Element.Document, + Document document => document, + _ => null + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/APIObjectDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/APIObjectDescriptor.cs new file mode 100644 index 000000000..245dd28d5 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/APIObjectDescriptor.cs @@ -0,0 +1,26 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ApiObjectDescriptor : Descriptor, IDescriptorCollector; \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/AnalyticalLinkTypeDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/AnalyticalLinkTypeDescriptor.cs new file mode 100644 index 000000000..4c6a465e8 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/AnalyticalLinkTypeDescriptor.cs @@ -0,0 +1,55 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Structure; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class AnalyticalLinkTypeDescriptor(AnalyticalLinkType analyticalLinkType) : ElementDescriptor(analyticalLinkType) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(AnalyticalLinkType.IsValidAnalyticalFixityState) => ResolveIsValidAnalyticalFixityState, + _ => null + }; + + IVariant ResolveIsValidAnalyticalFixityState() + { + var values = Enum.GetValues(typeof(AnalyticalFixityState)); + var variants = Variants.Values(values.Length); + foreach (AnalyticalFixityState state in values) + { + var result = AnalyticalLinkType.IsValidAnalyticalFixityState(state); + variants.Add(result, $"{state}: {result}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ApplicationDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ApplicationDescriptor.cs new file mode 100644 index 000000000..dce39ff33 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ApplicationDescriptor.cs @@ -0,0 +1,43 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.Macros; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ApplicationDescriptor : Descriptor, IDescriptorExtension +{ + private readonly Autodesk.Revit.ApplicationServices.Application _application; + + public ApplicationDescriptor(Autodesk.Revit.ApplicationServices.Application application) + { + _application = application; + Name = application.VersionName; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("GetFormulaFunctions", () => Variants.Value(FormulaManager.GetFunctions())); + manager.Register("GetFormulaOperators", () => Variants.Value(FormulaManager.GetOperators())); + manager.Register(nameof(MacroManager.GetMacroManager), () => Variants.Value(MacroManager.GetMacroManager(_application))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/AreaVolumeSettingsDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/AreaVolumeSettingsDescriptor.cs new file mode 100644 index 000000000..1b574b1b8 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/AreaVolumeSettingsDescriptor.cs @@ -0,0 +1,61 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class AreaVolumeSettingsDescriptor(AreaVolumeSettings settings) : ElementDescriptor(settings) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(AreaVolumeSettings.GetAreaVolumeSettings) => ResolveGet, + nameof(AreaVolumeSettings.GetSpatialElementBoundaryLocation) => ResolveGetSpatialElementBoundaryLocation, + _ => null + }; + + IVariant ResolveGet() + { + return Variants.Value(AreaVolumeSettings.GetAreaVolumeSettings(settings.Document)); + } + + IVariant ResolveGetSpatialElementBoundaryLocation() + { + var conditions = Enum.GetValues(typeof(SpatialElementType)); + var variants = Variants.Values(conditions.Length); + + foreach (SpatialElementType condition in conditions) + { + var result = settings.GetSpatialElementBoundaryLocation(condition); + variants.Add(result, $"{condition}: {result}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertiesDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertiesDescriptor.cs new file mode 100644 index 000000000..ed3b7d531 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertiesDescriptor.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Visual; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class AssetPropertiesDescriptor(AssetProperties assetProperties) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(AssetProperties.Get) => ResolveAssetProperties, + nameof(AssetProperties.FindByName) => ResolveAssetProperties, + _ => null + }; + + IVariant ResolveAssetProperties() + { + var capacity = assetProperties.Size; + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var property = assetProperties.Get(i); + variants.Add(property, property.Name); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertyDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertyDescriptor.cs new file mode 100644 index 000000000..4e38f33b1 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/AssetPropertyDescriptor.cs @@ -0,0 +1,57 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Visual; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class AssetPropertyDescriptor(AssetProperty assetProperty) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(AssetProperty.GetTypeName) => ResolveGetTypeName, + nameof(AssetProperty.GetConnectedProperty) => ResolveConnectedProperty, + _ => null + }; + + IVariant ResolveConnectedProperty() + { + var capacity = assetProperty.NumberOfConnectedProperties; + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var property = assetProperty.GetConnectedProperty(i); + variants.Add(property, property.Name); + } + + return variants.Consume(); + } + + IVariant ResolveGetTypeName() + { + return Variants.Value(AssetProperty.GetTypeName(assetProperty.Type)); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/BasePointDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/BasePointDescriptor.cs new file mode 100644 index 000000000..79ee31a6c --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/BasePointDescriptor.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class BasePointDescriptor(BasePoint basePoint) : ElementDescriptor(basePoint) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(BasePoint.GetSurveyPoint) => ResolveGetSurveyPoint, + nameof(BasePoint.GetProjectBasePoint) => ResolveGetProjectBasePoint, + _ => null + }; + + IVariant ResolveGetSurveyPoint() + { + return Variants.Value(BasePoint.GetSurveyPoint(basePoint.Document)); + } + + IVariant ResolveGetProjectBasePoint() + { + return Variants.Value(BasePoint.GetProjectBasePoint(basePoint.Document)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/BoundarySegmentDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/BoundarySegmentDescriptor.cs new file mode 100644 index 000000000..06c8aa942 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/BoundarySegmentDescriptor.cs @@ -0,0 +1,38 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class BoundarySegmentDescriptor : Descriptor, IDescriptorCollector +{ + public BoundarySegmentDescriptor(BoundarySegment boundarySegment) + { + var curve = boundarySegment.GetCurve(); + Name = curve switch + { + null => $"ID{boundarySegment.ElementId}", + _ => $"ID{boundarySegment.ElementId}, {curve.Length.ToString(CultureInfo.InvariantCulture)} ft", + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/BoundingBoxXyzDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/BoundingBoxXyzDescriptor.cs new file mode 100644 index 000000000..d4c2fdfc6 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/BoundingBoxXyzDescriptor.cs @@ -0,0 +1,164 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class BoundingBoxXyzDescriptor(BoundingBoxXYZ box) : Descriptor, IDescriptorResolver, IDescriptorExtension, IContextMenuConnector +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + "Bounds" => ResolveBounds, + "MinEnabled" => ResolveMinEnabled, + "MaxEnabled" => ResolveMaxEnabled, + "BoundEnabled" => ResolveBoundEnabled, + _ => null + }; + + IVariant ResolveBounds() + { + return Variants.Values(2) + .Add(box.get_Bounds(0), "Bound 0") + .Add(box.get_Bounds(1), "Bound 1") + .Consume(); + } + + IVariant ResolveMinEnabled() + { + var minEnabled0 = box.get_MinEnabled(0); + var minEnabled1 = box.get_MinEnabled(1); + var minEnabled2 = box.get_MinEnabled(2); + + return Variants.Values(3) + .Add(minEnabled0, $"Dimension 0: {minEnabled0}") + .Add(minEnabled1, $"Dimension 1: {minEnabled1}") + .Add(minEnabled2, $"Dimension 2: {minEnabled2}") + .Consume(); + } + + IVariant ResolveMaxEnabled() + { + var maxEnabled0 = box.get_MaxEnabled(0); + var maxEnabled1 = box.get_MaxEnabled(1); + var maxEnabled2 = box.get_MaxEnabled(2); + + return Variants.Values(3) + .Add(maxEnabled0, $"Dimension 0: {maxEnabled0}") + .Add(maxEnabled1, $"Dimension 1: {maxEnabled1}") + .Add(maxEnabled2, $"Dimension 2: {maxEnabled2}") + .Consume(); + } + + IVariant ResolveBoundEnabled() + { + var boundEnabled00 = box.get_BoundEnabled(0, 0); + var boundEnabled01 = box.get_BoundEnabled(0, 1); + var boundEnabled02 = box.get_BoundEnabled(0, 2); + var boundEnabled10 = box.get_BoundEnabled(1, 0); + var boundEnabled11 = box.get_BoundEnabled(1, 1); + var boundEnabled12 = box.get_BoundEnabled(1, 2); + + return Variants.Values(6) + .Add(boundEnabled00, $"Bound 0, dimension 0: {boundEnabled00}") + .Add(boundEnabled01, $"Bound 0, dimension 1: {boundEnabled01}") + .Add(boundEnabled02, $"Bound 0, dimension 2: {boundEnabled02}") + .Add(boundEnabled10, $"Bound 1, dimension 0: {boundEnabled10}") + .Add(boundEnabled11, $"Bound 1, dimension 1: {boundEnabled11}") + .Add(boundEnabled12, $"Bound 1, dimension 2: {boundEnabled12}") + .Consume(); + } + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("Centroid", () => Variants.Value((box.Min + box.Max) / 2)); + manager.Register("Vertices", () => Variants.Values(8) + .Add(new XYZ(box.Min.X, box.Min.Y, box.Min.Z)) + .Add(new XYZ(box.Min.X, box.Min.Y, box.Max.Z)) + .Add(new XYZ(box.Min.X, box.Max.Y, box.Min.Z)) + .Add(new XYZ(box.Min.X, box.Max.Y, box.Max.Z)) + .Add(new XYZ(box.Max.X, box.Min.Y, box.Min.Z)) + .Add(new XYZ(box.Max.X, box.Min.Y, box.Max.Z)) + .Add(new XYZ(box.Max.X, box.Max.Y, box.Min.Z)) + .Add(new XYZ(box.Max.X, box.Max.Y, box.Max.Z)) + .Consume()); + + manager.Register("Volume", () => + { + var length = box.Max.X - box.Min.X; + var width = box.Max.Y - box.Min.Y; + var height = box.Max.Z - box.Min.Z; + + return Variants.Value(length * width * height); + }); + + manager.Register("SurfaceArea", () => + { + var length = box.Max.X - box.Min.X; + var width = box.Max.Y - box.Min.Y; + var height = box.Max.Z - box.Min.Z; + + var area1 = length * width; + var area2 = length * height; + var area3 = width * height; + + return Variants.Value(2 * (area1 + area2 + area3)); + }); + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetCommand(box, VisualizeFace) + .SetShortcut(Key.F8); + + async Task VisualizeFace(BoundingBoxXYZ boundingBox) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(boundingBox); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize BoundingBox error"); + notificationService.ShowError("Visualization error", exception); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CategoryDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CategoryDescriptor.cs new file mode 100644 index 000000000..44aff8876 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CategoryDescriptor.cs @@ -0,0 +1,103 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CategoryDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension, IDescriptorExtension +{ + private readonly Category _category; + + public CategoryDescriptor(Category category) + { + _category = category; + Name = category.Name; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + "AllowsVisibilityControl" => ResolveAllowsVisibilityControl, + "Visible" => ResolveVisible, + nameof(Category.GetGraphicsStyle) => ResolveGetGraphicsStyle, + nameof(Category.GetLinePatternId) => ResolveGetLinePatternId, + nameof(Category.GetLineWeight) => ResolveGetLineWeight, + _ => null + }; + + IVariant ResolveGetLineWeight() + { + return Variants.Values(2) + .Add(_category.GetLineWeight(GraphicsStyleType.Cut), "Cut") + .Add(_category.GetLineWeight(GraphicsStyleType.Projection), "Projection") + .Consume(); + } + + IVariant ResolveGetLinePatternId() + { + return Variants.Values(2) + .Add(_category.GetLinePatternId(GraphicsStyleType.Cut), "Cut") + .Add(_category.GetLinePatternId(GraphicsStyleType.Projection), "Projection") + .Consume(); + } + + IVariant ResolveGetGraphicsStyle() + { + return Variants.Values(2) + .Add(_category.GetGraphicsStyle(GraphicsStyleType.Cut), "Cut") + .Add(_category.GetGraphicsStyle(GraphicsStyleType.Projection), "Projection") + .Consume(); + } + + IVariant ResolveAllowsVisibilityControl() + { + return Variants.Value(_category.get_AllowsVisibilityControl(Context.ActiveView), "Active view"); + } + + IVariant ResolveVisible() + { + return Variants.Value(_category.get_Visible(Context.ActiveView), "Active view"); + } + } + + public void RegisterExtensions(IExtensionManager manager) + { +#if !REVIT2023_OR_GREATER + manager.Register("BuiltInCategory", () => Variants.Value((BuiltInCategory) _category.Id.IntegerValue)); +#endif + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("GetElements", context => + { + return Variants.Value(context +#if REVIT2023_OR_GREATER + .GetInstances(_category.BuiltInCategory)); +#else + .GetInstances((BuiltInCategory) _category.Id.IntegerValue)); +#endif + }); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CityDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CityDescriptor.cs new file mode 100644 index 000000000..3cd3655b9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CityDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CityDescriptor : Descriptor, IDescriptorCollector +{ + public CityDescriptor(City city) + { + Name = city.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ColorDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ColorDescriptor.cs new file mode 100644 index 000000000..3177ef635 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ColorDescriptor.cs @@ -0,0 +1,57 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using RevitLookup.Common.Utils; +using RevitLookup.Utils.Media; +using Color = Autodesk.Revit.DB.Color; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ColorDescriptor : Descriptor, IDescriptorExtension +{ + private readonly Color _color; + + public ColorDescriptor(Color color) + { + _color = color; + Name = color.IsValid ? $"RGB: {color.Red} {color.Green} {color.Blue}" : "The color represents uninitialized/invalid value"; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("HEX", () => Variants.Value(ColorRepresentationUtils.ColorToHex(_color.GetDrawingColor()))); + manager.Register("HEX int", () => Variants.Value(ColorRepresentationUtils.ColorToHexInteger(_color.GetDrawingColor()))); + manager.Register("RGB", () => Variants.Value(ColorRepresentationUtils.ColorToRgb(_color.GetDrawingColor()))); + manager.Register("HSL", () => Variants.Value(ColorRepresentationUtils.ColorToHsl(_color.GetDrawingColor()))); + manager.Register("HSV", () => Variants.Value(ColorRepresentationUtils.ColorToHsv(_color.GetDrawingColor()))); + manager.Register("CMYK", () => Variants.Value(ColorRepresentationUtils.ColorToCmyk(_color.GetDrawingColor()))); + manager.Register("HSB", () => Variants.Value(ColorRepresentationUtils.ColorToHsb(_color.GetDrawingColor()))); + manager.Register("HSI", () => Variants.Value(ColorRepresentationUtils.ColorToHsi(_color.GetDrawingColor()))); + manager.Register("HWB", () => Variants.Value(ColorRepresentationUtils.ColorToHwb(_color.GetDrawingColor()))); + manager.Register("NCol", () => Variants.Value(ColorRepresentationUtils.ColorToNCol(_color.GetDrawingColor()))); + manager.Register("CIELAB", () => Variants.Value(ColorRepresentationUtils.ColorToCielab(_color.GetDrawingColor()))); + manager.Register("CIEXYZ", () => Variants.Value(ColorRepresentationUtils.ColorToCieXyz(_color.GetDrawingColor()))); + manager.Register("VEC4", () => Variants.Value(ColorRepresentationUtils.ColorToFloat(_color.GetDrawingColor()))); + manager.Register("Decimal", () => Variants.Value(ColorRepresentationUtils.ColorToDecimal(_color.GetDrawingColor()))); + manager.Register("Name", () => Variants.Value(ColorRepresentationUtils.GetColorName(_color.GetDrawingColor()))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs new file mode 100644 index 000000000..d50afb140 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ColorMediaDescriptor.cs @@ -0,0 +1,56 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using RevitLookup.Common.Utils; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ColorMediaDescriptor : Descriptor, IDescriptorExtension +{ + private readonly Color _color; + + public ColorMediaDescriptor(Color color) + { + _color = color; + Name = $"RGB: {color.R} {color.B} {color.B}"; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("HEX", () => Variants.Value(ColorRepresentationUtils.ColorToHex(_color.GetDrawingColor()))); + manager.Register("HEX int", () => Variants.Value(ColorRepresentationUtils.ColorToHexInteger(_color.GetDrawingColor()))); + manager.Register("RGB", () => Variants.Value(ColorRepresentationUtils.ColorToRgb(_color.GetDrawingColor()))); + manager.Register("HSL", () => Variants.Value(ColorRepresentationUtils.ColorToHsl(_color.GetDrawingColor()))); + manager.Register("HSV", () => Variants.Value(ColorRepresentationUtils.ColorToHsv(_color.GetDrawingColor()))); + manager.Register("CMYK", () => Variants.Value(ColorRepresentationUtils.ColorToCmyk(_color.GetDrawingColor()))); + manager.Register("HSB", () => Variants.Value(ColorRepresentationUtils.ColorToHsb(_color.GetDrawingColor()))); + manager.Register("HSI", () => Variants.Value(ColorRepresentationUtils.ColorToHsi(_color.GetDrawingColor()))); + manager.Register("HWB", () => Variants.Value(ColorRepresentationUtils.ColorToHwb(_color.GetDrawingColor()))); + manager.Register("NCol", () => Variants.Value(ColorRepresentationUtils.ColorToNCol(_color.GetDrawingColor()))); + manager.Register("CIELAB", () => Variants.Value(ColorRepresentationUtils.ColorToCielab(_color.GetDrawingColor()))); + manager.Register("CIEXYZ", () => Variants.Value(ColorRepresentationUtils.ColorToCieXyz(_color.GetDrawingColor()))); + manager.Register("VEC4", () => Variants.Value(ColorRepresentationUtils.ColorToFloat(_color.GetDrawingColor()))); + manager.Register("Decimal", () => Variants.Value(ColorRepresentationUtils.ColorToDecimal(_color.GetDrawingColor()))); + manager.Register("Name", () => Variants.Value(ColorRepresentationUtils.GetColorName(_color.GetDrawingColor()))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureDescriptor.cs new file mode 100644 index 000000000..575cf3553 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureDescriptor.cs @@ -0,0 +1,396 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public class CompoundStructureDescriptor(CompoundStructure compoundStructure) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(CompoundStructure.CanLayerBeStructuralMaterial) => ResolveCanLayerBeStructuralMaterial, + nameof(CompoundStructure.CanLayerBeVariable) => ResolveCanLayerBeVariable, + nameof(CompoundStructure.CanLayerWidthBeNonZero) => ResolveCanLayerWidthBeNonZero, + nameof(CompoundStructure.GetAdjacentRegions) => ResolveGetAdjacentRegions, + nameof(CompoundStructure.GetCoreBoundaryLayerIndex) => ResolveGetCoreBoundaryLayerIndex, + nameof(CompoundStructure.GetDeckEmbeddingType) => ResolveGetDeckEmbeddingType, + nameof(CompoundStructure.GetDeckProfileId) => ResolveGetDeckProfileId, + nameof(CompoundStructure.GetLayerAssociatedToRegion) => ResolveGetLayerAssociatedToRegion, + nameof(CompoundStructure.GetLayerFunction) => ResolveGetLayerFunction, + nameof(CompoundStructure.GetLayerWidth) => ResolveGetLayerWidth, + nameof(CompoundStructure.GetMaterialId) => ResolveGetMaterialId, + nameof(CompoundStructure.GetNumberOfShellLayers) => ResolveGetNumberOfShellLayers, + nameof(CompoundStructure.GetOffsetForLocationLine) => ResolveGetOffsetForLocationLine, + nameof(CompoundStructure.GetPreviousNonZeroLayerIndex) => ResolveGetPreviousNonZeroLayerIndex, + nameof(CompoundStructure.GetRegionEnvelope) => ResolveGetRegionEnvelope, + nameof(CompoundStructure.GetRegionsAssociatedToLayer) => ResolveGetRegionsAssociatedToLayer, + nameof(CompoundStructure.GetSegmentCoordinate) => ResolveGetSegmentCoordinate, + nameof(CompoundStructure.GetSegmentOrientation) => ResolveGetSegmentOrientation, + nameof(CompoundStructure.GetWallSweepsInfo) => ResolveGetWallSweepsInfo, + nameof(CompoundStructure.GetWidth) when parameters.Length == 1 => ResolveGetWidth, + nameof(CompoundStructure.IsCoreLayer) => ResolveIsCoreLayer, + nameof(CompoundStructure.IsRectangularRegion) => ResolveIsRectangularRegion, + nameof(CompoundStructure.IsSimpleRegion) => ResolveIsSimpleRegion, + nameof(CompoundStructure.IsStructuralDeck) => ResolveIsStructuralDeck, + nameof(CompoundStructure.ParticipatesInWrapping) => ResolveParticipatesInWrapping, + _ => null + }; + + IVariant ResolveCanLayerBeStructuralMaterial() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.CanLayerBeStructuralMaterial(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanLayerBeVariable() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.CanLayerBeVariable(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanLayerWidthBeNonZero() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.CanLayerWidthBeNonZero(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetAdjacentRegions() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values>(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.GetAdjacentRegions(i); + variants.Add(result, $"Region" + $" {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetCoreBoundaryLayerIndex() + { + var values = Enum.GetValues(typeof(ShellLayerType)); + var variants = Variants.Values(values.Length); + + foreach (ShellLayerType value in values) + { + var result = compoundStructure.GetCoreBoundaryLayerIndex(value); + variants.Add(result, $"{value.ToString()}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetDeckEmbeddingType() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetDeckEmbeddingType(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetLayerAssociatedToRegion() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.GetLayerAssociatedToRegion(i); + variants.Add(result, $"Region {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetLayerFunction() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetLayerFunction(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetDeckProfileId() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetDeckProfileId(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetLayerWidth() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetLayerWidth(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetMaterialId() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetMaterialId(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetNumberOfShellLayers() + { + var values = Enum.GetValues(typeof(ShellLayerType)); + var variants = Variants.Values(values.Length); + + foreach (ShellLayerType value in values) + { + var result = compoundStructure.GetNumberOfShellLayers(value); + variants.Add(result, $"{value.ToString()}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetOffsetForLocationLine() + { + var values = Enum.GetValues(typeof(WallLocationLine)); + var variants = Variants.Values(values.Length); + + foreach (WallLocationLine value in values) + { + var result = compoundStructure.GetOffsetForLocationLine(value); + variants.Add(result, $"{value.ToString()}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetPreviousNonZeroLayerIndex() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetPreviousNonZeroLayerIndex(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetRegionEnvelope() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.GetRegionEnvelope(i); + variants.Add(result, $"Region {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetRegionsAssociatedToLayer() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values>(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.GetRegionsAssociatedToLayer(i); + variants.Add(result, $"Layer {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetSegmentCoordinate() + { + var segmentCount = compoundStructure.GetSegmentIds().Count; + var variants = Variants.Values(segmentCount); + for (var i = 0; i < segmentCount; i++) + { + var result = compoundStructure.GetSegmentCoordinate(i); + variants.Add(result, $"Segment {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetSegmentOrientation() + { + var segmentCount = compoundStructure.GetSegmentIds().Count; + var variants = Variants.Values(segmentCount); + for (var i = 0; i < segmentCount; i++) + { + var result = compoundStructure.GetSegmentOrientation(i); + variants.Add(result, $"Segment {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetWallSweepsInfo() + { + var values = Enum.GetValues(typeof(WallSweepType)); + var variants = Variants.Values>(values.Length); + + foreach (WallSweepType value in values) + { + var result = compoundStructure.GetWallSweepsInfo(value); + variants.Add(result, value.ToString()); + } + + return variants.Consume(); + } + + IVariant ResolveGetWidth() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.GetWidth(i); + variants.Add(result, $"Region {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsCoreLayer() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.IsCoreLayer(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsRectangularRegion() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.IsRectangularRegion(i); + variants.Add(result, $"Region {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsSimpleRegion() + { + var regionsCount = compoundStructure.GetRegionIds().Count; + var variants = Variants.Values(regionsCount); + + for (var i = 0; i < regionsCount; i++) + { + var result = compoundStructure.IsSimpleRegion(i); + variants.Add(result, $"Region {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsStructuralDeck() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.IsStructuralDeck(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveParticipatesInWrapping() + { + var layerCount = compoundStructure.LayerCount; + var variants = Variants.Values(layerCount); + for (var i = 0; i < layerCount; i++) + { + var result = compoundStructure.ParticipatesInWrapping(i); + variants.Add(result, $"Layer {i}: {result}"); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureLayerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureLayerDescriptor.cs new file mode 100644 index 000000000..088bf38b5 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CompoundStructureLayerDescriptor.cs @@ -0,0 +1,31 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CompoundStructureLayerDescriptor : Descriptor +{ + public CompoundStructureLayerDescriptor(CompoundStructureLayer layer) + { + Name = layer.Function.ToString(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ConnectorManagerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ConnectorManagerDescriptor.cs new file mode 100644 index 000000000..bb76d0a84 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ConnectorManagerDescriptor.cs @@ -0,0 +1,51 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ConnectorManagerDescriptor(ConnectorManager connectorManager) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ConnectorManager.Lookup) => ResolveLookup, + _ => null + }; + + IVariant ResolveLookup() + { + var connectorSet = connectorManager.Connectors; + var capacity = connectorSet.Size; + var variants = Variants.Values(capacity); + + for (var i = 0; i < capacity; i++) + { + variants.Add(connectorManager.Lookup(i)); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CurtainGridDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CurtainGridDescriptor.cs new file mode 100644 index 000000000..28ddf52e6 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CurtainGridDescriptor.cs @@ -0,0 +1,80 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CurtainGridDescriptor(CurtainGrid curtainGrid) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(CurtainGrid.GetCell) => ResolveCells, + nameof(CurtainGrid.GetPanel) => ResolvePanels, + _ => null + }; + + IVariant ResolveCells() + { + var uLinesIds = (List) curtainGrid.GetUGridLineIds(); + var vLinesIds = (List) curtainGrid.GetVGridLineIds(); + uLinesIds.Add(ElementId.InvalidElementId); + vLinesIds.Add(ElementId.InvalidElementId); + var capacity = uLinesIds.Count * vLinesIds.Count; + + var variants = Variants.Values(capacity); + foreach (var uLineId in uLinesIds) + { + foreach (var vLineId in vLinesIds) + { + var cell = curtainGrid.GetCell(uLineId, vLineId); + variants.Add(cell, $"U {uLineId}, V {vLineId}"); + } + } + + return variants.Consume(); + } + + IVariant ResolvePanels() + { + var uLinesIds = (List) curtainGrid.GetUGridLineIds(); + var vLinesIds = (List) curtainGrid.GetVGridLineIds(); + uLinesIds.Add(ElementId.InvalidElementId); + vLinesIds.Add(ElementId.InvalidElementId); + var capacity = uLinesIds.Count * vLinesIds.Count; + + var variants = Variants.Values(capacity); + foreach (var uLineId in uLinesIds) + { + foreach (var vLineId in vLinesIds) + { + var panel = curtainGrid.GetPanel(uLineId, vLineId); + variants.Add(panel, $"U {uLineId}, V {vLineId} - {panel.Name}, ID{panel.Id}"); + } + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CurveDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CurveDescriptor.cs new file mode 100644 index 000000000..5866ffb57 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CurveDescriptor.cs @@ -0,0 +1,158 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using System.Reflection; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CurveDescriptor : Descriptor, IDescriptorResolver, IContextMenuConnector +{ + private readonly Curve _curve; + + public CurveDescriptor(Curve curve) + { + _curve = curve; + if (curve.IsBound || curve.IsCyclic) Name = $"{curve.Length.ToString(CultureInfo.InvariantCulture)} ft"; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Curve.GetEndPoint) => ResolveGetEndPoint, + nameof(Curve.GetEndParameter) => ResolveGetEndParameter, + nameof(Curve.GetEndPointReference) => ResolveGetEndPointReference, + nameof(Curve.Evaluate) => ResolveEvaluate, + _ => null + }; + + IVariant ResolveEvaluate() + { + var variants = Variants.Values(3); + var endParameter0 = _curve.GetEndParameter(0); + var endParameter1 = _curve.GetEndParameter(1); + var endParameterMid = (endParameter0 + endParameter1) / 2; + + variants.Add(_curve.Evaluate(endParameter0, false), $"Parameter {endParameter0.Round(3)}"); + variants.Add(_curve.Evaluate(endParameterMid, false), $"Parameter {endParameterMid.Round(3)}"); + variants.Add(_curve.Evaluate(endParameter1, false), $"Parameter {endParameter1.Round(3)}"); + + return variants.Consume(); + } + + IVariant ResolveGetEndPoint() + { + return Variants.Values(2) + .Add(_curve.GetEndPoint(0), "Point 0") + .Add(_curve.GetEndPoint(1), "Point 1") + .Consume(); + } + + IVariant ResolveGetEndParameter() + { + return Variants.Values(2) + .Add(_curve.GetEndParameter(0), "Parameter 0") + .Add(_curve.GetEndParameter(1), "Parameter 1") + .Consume(); + } + + IVariant ResolveGetEndPointReference() + { + return Variants.Values(2) + .Add(_curve.GetEndPointReference(0), "Reference 0") + .Add(_curve.GetEndPointReference(1), "Reference 1") + .Consume(); + } + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { +#if REVIT2023_OR_GREATER + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_curve, SelectCurve) + .SetShortcut(Key.F6); + + contextMenu.AddMenuItem("ShowMenuItem") + .SetCommand(_curve, ShowCurve) + .SetShortcut(Key.F7); +#endif + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability((_curve.IsBound || _curve.IsCyclic) && _curve.ApproximateLength > 1e-6) + .SetCommand(_curve, VisualizeCurve) + .SetShortcut(Key.F8); + + async Task VisualizeCurve(Curve curve) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(curve); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize curve error"); + notificationService.ShowError("Visualization error", exception); + } + } + +#if REVIT2023_OR_GREATER + void SelectCurve(Curve curve) + { + if (Context.ActiveUiDocument is null) return; + if (curve.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetReferences([curve.Reference])); + } + + void ShowCurve(Curve curve) + { + if (Context.ActiveUiDocument is null) return; + if (curve.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(application => + { + var uiDocument = application.ActiveUIDocument; + if (uiDocument is null) return; + + var element = curve.Reference.ElementId.ToElement(uiDocument.Document); + if (element is not null) uiDocument.ShowElements(element); + + uiDocument.Selection.SetReferences([curve.Reference]); + }); + } +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/CurveElementDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CurveElementDescriptor.cs new file mode 100644 index 000000000..44b1ed304 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CurveElementDescriptor.cs @@ -0,0 +1,134 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class CurveElementDescriptor(CurveElement element) : ElementDescriptor(element) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(CurveElement.GetAdjoinedCurveElements) => ResolveAdjoinedCurveElements, + nameof(CurveElement.HasTangentLocks) => ResolveHasTangentLocks, + nameof(CurveElement.GetTangentLock) => ResolveTangentLock, + nameof(CurveElement.HasTangentJoin) => ResolveTangentJoin, + nameof(CurveElement.IsAdjoinedCurveElement) => ResolveIsAdjoinedCurveElement, + _ => null + }; + + IVariant ResolveAdjoinedCurveElements() + { + var startCurveElements = element.GetAdjoinedCurveElements(0); + var endCurveElements = element.GetAdjoinedCurveElements(1); + + return Variants.Values>(2) + .Add(startCurveElements, "Point 0") + .Add(endCurveElements, "Point 1") + .Consume(); + } + + IVariant ResolveHasTangentLocks() + { + var startHasTangentLocks = element.HasTangentLocks(0); + var endHasTangentLocks = element.HasTangentLocks(1); + + return Variants.Values(2) + .Add(startHasTangentLocks, $"Point 0: {startHasTangentLocks}") + .Add(endHasTangentLocks, $"Point 1: {endHasTangentLocks}") + .Consume(); + } + + IVariant ResolveTangentLock() + { + var startCurveElements = element.GetAdjoinedCurveElements(0); + var endCurveElements = element.GetAdjoinedCurveElements(1); + var variants = Variants.Values(startCurveElements.Count + endCurveElements.Count); + + foreach (var id in startCurveElements) + { + if (!element.HasTangentJoin(0, id)) continue; + + var result = element.GetTangentLock(0, id); + variants.Add(result, $"Point 0, {id}: {result}"); + } + + foreach (var id in endCurveElements) + { + if (!element.HasTangentJoin(1, id)) continue; + + var result = element.GetTangentLock(1, id); + variants.Add(result, $"Point 1, {id}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveTangentJoin() + { + var startCurveElements = element.GetAdjoinedCurveElements(0); + var endCurveElements = element.GetAdjoinedCurveElements(1); + var variants = Variants.Values(startCurveElements.Count + endCurveElements.Count); + + foreach (var id in startCurveElements) + { + var result = element.HasTangentJoin(0, id); + variants.Add(result, $"Point 0, {id}: {result}"); + } + + foreach (var id in endCurveElements) + { + var result = element.HasTangentJoin(1, id); + variants.Add(result, $"Point 1, {id}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsAdjoinedCurveElement() + { + var startCurveElements = element.GetAdjoinedCurveElements(0); + var endCurveElements = element.GetAdjoinedCurveElements(1); + var variants = Variants.Values(startCurveElements.Count + endCurveElements.Count); + + foreach (var id in startCurveElements) + { + var result = element.IsAdjoinedCurveElement(0, id); + variants.Add(result, $"Point 0, {id}: {result}"); + } + + foreach (var id in endCurveElements) + { + var result = element.IsAdjoinedCurveElement(1, id); + variants.Add(result, $"Point 1, {id}: {result}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Fields.cs b/source/RevitLookup/Core/Decomposition/Descriptors/CylindricalFaceDescriptor.cs similarity index 59% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Fields.cs rename to source/RevitLookup/Core/Decomposition/Descriptors/CylindricalFaceDescriptor.cs index 682db9780..464bed00d 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Fields.cs +++ b/source/RevitLookup/Core/Decomposition/Descriptors/CylindricalFaceDescriptor.cs @@ -19,32 +19,27 @@ // (Rights in Technical Data and Computer Software), as applicable. using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; -namespace RevitLookup.Core.Engine; +namespace RevitLookup.Core.Decomposition.Descriptors; -public sealed partial class DescriptorBuilder +public sealed class CylindricalFaceDescriptor(CylindricalFace face) : FaceDescriptor(face), IDescriptorResolver { - private void AddFields(BindingFlags bindingFlags) + public Func? Resolve(string target, ParameterInfo[] parameters) { - if (!_settings.IncludeFields) return; - - var members = _type.GetFields(bindingFlags); - foreach (var member in members) + return target switch { - if (member.IsSpecialName) continue; - - var value = Evaluate(member); - WriteDescriptor(member, value, null); + "Radius" => ResolveRadius, + _ => null + }; + + IVariant ResolveRadius() + { + return Variants.Values(2) + .Add(face.get_Radius(0), "Radius 0") + .Add(face.get_Radius(1), "Radius 1") + .Consume(); } } - - private object Evaluate(FieldInfo member) - { - _clockDiagnoser.Start(); - _memoryDiagnoser.Start(); - var value = member.GetValue(_obj); - _memoryDiagnoser.Stop(); - _clockDiagnoser.Stop(); - return value; - } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DatumPlaneDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DatumPlaneDescriptor.cs new file mode 100644 index 000000000..b549f4112 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DatumPlaneDescriptor.cs @@ -0,0 +1,132 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DatumPlaneDescriptor(DatumPlane datumPlane) : ElementDescriptor(datumPlane) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { +#if REVIT2025_OR_GREATER //TODO Fatal https://github.com/jeremytammik/RevitLookup/issues/225 + nameof(DatumPlane.CanBeVisibleInView) => Variants.Disabled, + nameof(DatumPlane.GetPropagationViews) => Variants.Disabled, +#else + nameof(DatumPlane.CanBeVisibleInView) => ResolveCanBeVisibleInView, + nameof(DatumPlane.GetPropagationViews) => ResolvePropagationViews, +#endif + nameof(DatumPlane.GetDatumExtentTypeInView) => ResolveDatumExtentTypeInView, + nameof(DatumPlane.HasBubbleInView) => ResolveHasBubbleInView, + nameof(DatumPlane.IsBubbleVisibleInView) => ResolveBubbleVisibleInView, + nameof(DatumPlane.GetCurvesInView) => ResolveGetCurvesInView, + nameof(DatumPlane.GetLeader) => ResolveGetLeader, + _ => null + }; +#if !REVIT2025_OR_GREATER + IVariant ResolveCanBeVisibleInView() + { + var views = datumPlane.Document.EnumerateInstances().ToArray(); + var variants = Variants.Values(views.Length); + + foreach (var view in views) + { + var result = datumPlane.CanBeVisibleInView(view); + variants.Add(result, $"{view.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolvePropagationViews() + { + var views = datumPlane.Document.EnumerateInstances().ToArray(); + var variants = Variants.Values>(views.Length); + + foreach (var view in views) + { + if (!datumPlane.CanBeVisibleInView(view)) continue; + + var result = datumPlane.GetPropagationViews(view); + variants.Add(result, view.Name); + } + + return variants.Consume(); + } +#endif + + IVariant ResolveDatumExtentTypeInView() + { + var resultEnd0 = datumPlane.GetDatumExtentTypeInView(DatumEnds.End0, Context.ActiveView); + var resultEnd1 = datumPlane.GetDatumExtentTypeInView(DatumEnds.End1, Context.ActiveView); + + return Variants.Values(2) + .Add(resultEnd0, $"End 0, Active view: {resultEnd0}") + .Add(resultEnd1, $"End 1, Active view: {resultEnd1}") + .Consume(); + } + + IVariant ResolveHasBubbleInView() + { + var resultEnd0 = datumPlane.HasBubbleInView(DatumEnds.End0, Context.ActiveView); + var resultEnd1 = datumPlane.HasBubbleInView(DatumEnds.End1, Context.ActiveView); + + return Variants.Values(2) + .Add(resultEnd0, $"End 0, Active view: {resultEnd0}") + .Add(resultEnd1, $"End 1, Active view: {resultEnd1}") + .Consume(); + } + + IVariant ResolveBubbleVisibleInView() + { + var resultEnd0 = datumPlane.IsBubbleVisibleInView(DatumEnds.End0, Context.ActiveView); + var resultEnd1 = datumPlane.IsBubbleVisibleInView(DatumEnds.End1, Context.ActiveView); + + return Variants.Values(2) + .Add(resultEnd0, $"End 0, Active view: {resultEnd0}") + .Add(resultEnd1, $"End 1, Active view: {resultEnd1}") + .Consume(); + } + + IVariant ResolveGetCurvesInView() + { + return Variants.Values>(2) + .Add(datumPlane.GetCurvesInView(DatumExtentType.Model, Context.ActiveView), "Model, Active view") + .Add(datumPlane.GetCurvesInView(DatumExtentType.ViewSpecific, Context.ActiveView), "ViewSpecific, Active view") + .Consume(); + } + + IVariant ResolveGetLeader() + { + return Variants.Values(2) + .Add(datumPlane.GetLeader(DatumEnds.End0, Context.ActiveView), "End 0, Active view") + .Add(datumPlane.GetLeader(DatumEnds.End1, Context.ActiveView), "End 1, Active view") + .Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionBindingMapIteratorDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionBindingMapIteratorDescriptor.cs new file mode 100644 index 000000000..d31cc02cf --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionBindingMapIteratorDescriptor.cs @@ -0,0 +1,35 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DefinitionBindingMapIteratorDescriptor(DefinitionBindingMapIterator iterator) : Descriptor, IDescriptorRedirector +{ + private readonly object _object = new KeyValuePair(iterator.Key, iterator.Current); + + public bool TryRedirect(string target, out object result) + { + result = _object; + return true; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionDescriptor.cs new file mode 100644 index 000000000..3b1d413d4 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionDescriptor.cs @@ -0,0 +1,41 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DefinitionDescriptor : Descriptor, IDescriptorCollector +{ + public DefinitionDescriptor(Definition definition) + { + Name = CreateName(definition); + } + + private static string CreateName(Definition definition) + { + return definition switch + { + InternalDefinition internalDefinition when internalDefinition.BuiltInParameter != BuiltInParameter.INVALID => internalDefinition.BuiltInParameter.ToString(), + _ => definition.Name + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionGroupDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionGroupDescriptor.cs new file mode 100644 index 000000000..776f79a2f --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DefinitionGroupDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DefinitionGroupDescriptor : Descriptor, IDescriptorCollector +{ + public DefinitionGroupDescriptor(DefinitionGroup group) + { + Name = group.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DependencyObjectDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DependencyObjectDescriptor.cs new file mode 100644 index 000000000..011196fc9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DependencyObjectDescriptor.cs @@ -0,0 +1,43 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DependencyObjectDescriptor : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(DependencyObject.GetLocalValueEnumerator) => ResolveGetLocalValueEnumerator, + _ => null + }; + + IVariant ResolveGetLocalValueEnumerator() + { + return Variants.Empty(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DisposableDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DisposableDescriptor.cs new file mode 100644 index 000000000..158d6217d --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DisposableDescriptor.cs @@ -0,0 +1,26 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DisposableDescriptor : Descriptor, IDescriptorCollector; \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/DocumentDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/DocumentDescriptor.cs new file mode 100644 index 000000000..56d50262e --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/DocumentDescriptor.cs @@ -0,0 +1,137 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Lighting; +using Autodesk.Revit.DB.Structure; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +#if !REVIT2025_OR_GREATER +using Autodesk.Revit.DB.Macros; +#endif + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class DocumentDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension +{ + private readonly Document _document; + + public DocumentDescriptor(Document document) + { + _document = document; + Name = document.Title; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Document.Close) => Variants.Disabled, + nameof(Document.PlanTopologies) => ResolvePlanTopologies, + nameof(Document.GetDefaultElementTypeId) => ResolveDefaultElementTypeId, +#if REVIT2024_OR_GREATER + nameof(Document.GetUnusedElements) => ResolveGetUnusedElements, + nameof(Document.GetAllUnusedElements) => ResolveGetAllUnusedElements, +#endif + _ => null + }; + + IVariant ResolvePlanTopologies() + { + if (_document.IsReadOnly) return Variants.Empty(); + + var transaction = new Transaction(_document); + transaction.Start("Calculating plan topologies"); + var topologies = _document.PlanTopologies; + transaction.Commit(); + + return Variants.Value(topologies); + } + + IVariant ResolveDefaultElementTypeId() + { + var values = Enum.GetValues(typeof(ElementTypeGroup)); + var variants = Variants.Values(values.Length); + + foreach (ElementTypeGroup value in values) + { + var result = _document.GetDefaultElementTypeId(value); + if (result is not null && result != ElementId.InvalidElementId) + { + var element = result.ToElement(_document); + if (element is not null) + { + variants.Add(result, $"{value.ToString()}: {element.Name}"); + continue; + } + } + + variants.Add(result, $"{value.ToString()}: {result}"); + } + + return variants.Consume(); + } +#if REVIT2024_OR_GREATER + + IVariant ResolveGetUnusedElements() + { + return Variants.Value(_document.GetUnusedElements(new HashSet())); + } + + IVariant ResolveGetAllUnusedElements() + { + return Variants.Value(_document.GetAllUnusedElements(new HashSet())); + } +#endif + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(GlobalParametersManager.GetAllGlobalParameters), () => Variants.Value(GlobalParametersManager.GetAllGlobalParameters(_document))); + manager.Register(nameof(LightGroupManager.GetLightGroupManager), () => Variants.Value(LightGroupManager.GetLightGroupManager(_document))); +#if !REVIT2025_OR_GREATER + manager.Register(nameof(MacroManager.GetMacroManager), () => Variants.Value(MacroManager.GetMacroManager(_document))); +#endif +#if REVIT2022_OR_GREATER + manager.Register(nameof(TemporaryGraphicsManager.GetTemporaryGraphicsManager), () => Variants.Value(TemporaryGraphicsManager.GetTemporaryGraphicsManager(_document))); +#endif +#if REVIT2023_OR_GREATER + manager.Register(nameof(AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager), + () => Variants.Value(AnalyticalToPhysicalAssociationManager.GetAnalyticalToPhysicalAssociationManager(_document))); +#endif + if (_document.IsFamilyDocument) + { + manager.Register(nameof(FamilySizeTableManager.CreateFamilySizeTableManager), () => + { + var familyTableId = new ElementId(BuiltInParameter.RBS_LOOKUP_TABLE_NAME); + return Variants.Value(FamilySizeTableManager.GetFamilySizeTableManager(_document, familyTableId)); + }); + + manager.Register(nameof(LightFamily.GetLightFamily), () => Variants.Value(LightFamily.GetLightFamily(_document))); + } + + // Disabled: slow performance. + // manager.Register(nameof(WorksharingUtils.GetUserWorksetInfo), context => + // { + // var modelPath = context.IsModelInCloud ? context.GetCloudModelPath() : context.GetWorksharingCentralModelPath(); + // return WorksharingUtils.GetUserWorksetInfo(modelPath); + // }); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/EdgeDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/EdgeDescriptor.cs new file mode 100644 index 000000000..4f12292cd --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/EdgeDescriptor.cs @@ -0,0 +1,108 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class EdgeDescriptor : Descriptor, IDescriptorCollector, IContextMenuConnector +{ + private readonly Edge _edge; + + public EdgeDescriptor(Edge edge) + { + _edge = edge; + Name = $"{edge.ApproximateLength.ToString(CultureInfo.InvariantCulture)} ft"; + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { +#if REVIT2023_OR_GREATER + + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_edge, SelectEdge) + .SetShortcut(Key.F6); + + contextMenu.AddMenuItem("ShowMenuItem") + .SetCommand(_edge, ShowEdge) + .SetShortcut(Key.F7); +#endif + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability(_edge.ApproximateLength > 1e-6) + .SetCommand(_edge, VisualizeEdge) + .SetShortcut(Key.F8); + + async Task VisualizeEdge(Edge edge) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(edge); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize Edge error"); + notificationService.ShowError("Visualization error", exception); + } + } +#if REVIT2023_OR_GREATER + + void SelectEdge(Edge edge) + { + if (Context.ActiveUiDocument is null) return; + if (edge.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetReferences([edge.Reference])); + } + + void ShowEdge(Edge edge) + { + if (Context.ActiveUiDocument is null) return; + if (edge.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(application => + { + var uiDocument = application.ActiveUIDocument; + if (uiDocument is null) return; + + var element = edge.Reference.ElementId.ToElement(uiDocument.Document); + if (element is not null) uiDocument.ShowElements(element); + + uiDocument.Selection.SetReferences([edge.Reference]); + }); + } +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ElementDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ElementDescriptor.cs new file mode 100644 index 000000000..3917642b1 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ElementDescriptor.cs @@ -0,0 +1,385 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using Autodesk.Revit.DB.ExtensibleStorage; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public class ElementDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension, IContextMenuConnector +{ + private readonly Element _element; + + public ElementDescriptor(Element element) + { + _element = element; + Name = element.Name == string.Empty ? $"ID{element.Id}" : $"{element.Name}, ID{element.Id}"; + } + + public virtual Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Element.CanBeHidden) => ResolveCanBeHidden, + nameof(Element.IsHidden) => ResolveIsHidden, + nameof(Element.GetDependentElements) => ResolveGetDependentElements, + nameof(Element.GetMaterialIds) => ResolveGetMaterialIds, + nameof(Element.GetMaterialArea) => ResolveGetMaterialArea, + nameof(Element.GetMaterialVolume) => ResolveGetMaterialVolume, + nameof(Element.GetEntity) => ResolveGetEntity, + nameof(Element.GetPhaseStatus) => ResolvePhaseStatus, + nameof(Element.IsPhaseCreatedValid) => ResolveIsPhaseCreatedValid, + nameof(Element.IsPhaseDemolishedValid) => ResolveIsPhaseDemolishedValid, +#if REVIT2022_OR_GREATER + nameof(Element.IsDemolishedPhaseOrderValid) => ResolveIsDemolishedPhaseOrderValid, + nameof(Element.IsCreatedPhaseOrderValid) => ResolveIsCreatedPhaseOrderValid, +#endif + "BoundingBox" => ResolveBoundingBox, + "Geometry" => ResolveGeometry, + _ => null + }; + + IVariant ResolveGetMaterialArea() + { + var geometryMaterials = _element.GetMaterialIds(false); + var paintMaterials = _element.GetMaterialIds(true); + + var capacity = geometryMaterials.Count + paintMaterials.Count; + if (capacity == 0) return Variants.Empty>(); + + var variants = Variants.Values>(capacity); + foreach (var materialId in geometryMaterials) + { + var area = _element.GetMaterialArea(materialId, false); + variants.Add(new KeyValuePair(materialId, area)); + } + + foreach (var materialId in paintMaterials) + { + var area = _element.GetMaterialArea(materialId, true); + variants.Add(new KeyValuePair(materialId, area)); + } + + return variants.Consume(); + } + + IVariant ResolveGetMaterialVolume() + { + var geometryMaterials = _element.GetMaterialIds(false); + + if (geometryMaterials.Count == 0) return Variants.Empty>(); + + var variants = Variants.Values>(geometryMaterials.Count); + foreach (var materialId in geometryMaterials) + { + var area = _element.GetMaterialVolume(materialId); + variants.Add(new KeyValuePair(materialId, area)); + } + + return variants.Consume(); + } + + IVariant ResolveGetEntity() + { + var schemas = Schema.ListSchemas(); + var variants = Variants.Values(schemas.Count); + foreach (var schema in schemas) + { + if (!schema.ReadAccessGranted()) continue; + + var entity = _element.GetEntity(schema); + if (!entity.IsValid()) continue; + + variants.Add(entity, schema.SchemaName); + } + + return variants.Consume(); + } + + IVariant ResolveGeometry() + { + return Variants.Values(10) + .Add(_element.get_Geometry(new Options + { + View = Context.ActiveView, + ComputeReferences = true + }), "Active view") + .Add(_element.get_Geometry(new Options + { + View = Context.ActiveView, + IncludeNonVisibleObjects = true, + ComputeReferences = true + }), "Active view, including non-visible objects") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Coarse, + ComputeReferences = true + }), "Model, coarse detail level") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Fine, + ComputeReferences = true + }), "Model, fine detail level") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Medium, + ComputeReferences = true + }), "Model, medium detail level") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Undefined, + ComputeReferences = true + }), "Model, undefined detail level") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Coarse, + IncludeNonVisibleObjects = true, + ComputeReferences = true + }), "Model, coarse detail level, including non-visible objects") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Fine, + IncludeNonVisibleObjects = true, + ComputeReferences = true + }), "Model, fine detail level, including non-visible objects") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Medium, + IncludeNonVisibleObjects = true, + ComputeReferences = true + }), "Model, medium detail level, including non-visible objects") + .Add(_element.get_Geometry(new Options + { + DetailLevel = ViewDetailLevel.Undefined, + IncludeNonVisibleObjects = true, + ComputeReferences = true + }), "Model, undefined detail level, including non-visible objects") + .Consume(); + } + + IVariant ResolveGetMaterialIds() + { + return Variants.Values>(2) + .Add(_element.GetMaterialIds(true), "Paint materials") + .Add(_element.GetMaterialIds(false), "Geometry and compound structure materials") + .Consume(); + } + + IVariant ResolveBoundingBox() + { + return Variants.Values(2) + .Add(_element.get_BoundingBox(null), "Model") + .Add(_element.get_BoundingBox(Context.ActiveView), "Active view") + .Consume(); + } + + IVariant ResolveCanBeHidden() + { + return Variants.Value(_element.CanBeHidden(Context.ActiveView), "Active view"); + } + + IVariant ResolveIsHidden() + { + return Variants.Value(_element.IsHidden(Context.ActiveView), "Active view"); + } + + IVariant ResolveGetDependentElements() + { + return Variants.Value(_element.GetDependentElements(null)); + } + + IVariant ResolvePhaseStatus() + { + var phases = _element.Document.Phases; + var variants = Variants.Values(phases.Size); + foreach (Phase phase in phases) + { + var result = _element.GetPhaseStatus(phase.Id); + variants.Add(result, $"{phase.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsPhaseCreatedValid() + { + var phases = _element.Document.Phases; + var variants = Variants.Values(phases.Size); + foreach (Phase phase in phases) + { + var result = _element.IsPhaseCreatedValid(phase.Id); + variants.Add(result, $"{phase.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsPhaseDemolishedValid() + { + var phases = _element.Document.Phases; + var variants = Variants.Values(phases.Size); + foreach (Phase phase in phases) + { + var result = _element.IsPhaseDemolishedValid(phase.Id); + variants.Add(result, $"{phase.Name}: {result}"); + } + + return variants.Consume(); + } + +#if REVIT2022_OR_GREATER + IVariant ResolveIsCreatedPhaseOrderValid() + { + var phases = _element.Document.Phases; + var variants = Variants.Values(phases.Size); + foreach (Phase phase in phases) + { + var result = _element.IsCreatedPhaseOrderValid(phase.Id); + variants.Add(result, $"{phase.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsDemolishedPhaseOrderValid() + { + var phases = _element.Document.Phases; + var variants = Variants.Values(phases.Size); + foreach (Phase phase in phases) + { + var result = _element.IsDemolishedPhaseOrderValid(phase.Id); + variants.Add(result, $"{phase.Name}: {result}"); + } + + return variants.Consume(); + } + +#endif + } + + public virtual void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(ElementExtensions.CanBeMirrored), () => Variants.Value(_element.CanBeMirrored())); + manager.Register(nameof(JoinGeometryUtilsExtensions.GetJoinedElements), () => Variants.Value(_element.GetJoinedElements())); + manager.Register(nameof(SolidSolidCutUtils.GetCuttingSolids), () => Variants.Value(SolidSolidCutUtils.GetCuttingSolids(_element))); + manager.Register(nameof(SolidSolidCutUtils.GetSolidsBeingCut), () => Variants.Value(SolidSolidCutUtils.GetSolidsBeingCut(_element))); + manager.Register(nameof(SolidSolidCutUtils.IsAllowedForSolidCut), () => Variants.Value(SolidSolidCutUtils.IsAllowedForSolidCut(_element))); + manager.Register(nameof(SolidSolidCutUtils.IsElementFromAppropriateContext), () => Variants.Value(SolidSolidCutUtils.IsElementFromAppropriateContext(_element))); + manager.Register(nameof(WorksharingUtils.GetCheckoutStatus), () => Variants.Value(WorksharingUtils.GetCheckoutStatus(_element.Document, _element.Id))); + manager.Register(nameof(WorksharingUtils.GetWorksharingTooltipInfo), () => Variants.Value(WorksharingUtils.GetWorksharingTooltipInfo(_element.Document, _element.Id))); + manager.Register(nameof(WorksharingUtils.GetModelUpdatesStatus), () => Variants.Value(WorksharingUtils.GetModelUpdatesStatus(_element.Document, _element.Id))); + manager.Register(nameof(PartUtils.AreElementsValidForCreateParts), () => Variants.Value(PartUtils.AreElementsValidForCreateParts(_element.Document, [_element.Id]))); + } + + public virtual void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_element, SelectFace) + .SetShortcut(Key.F6); + + if (_element is not ElementType && _element is not Family) + { + contextMenu.AddMenuItem("ShowMenuItem") + .SetCommand(_element, ShowFace) + .SetShortcut(Key.F7); + } + + contextMenu.AddMenuItem("DeleteMenuItem") + .SetCommand(_element, DeleteElement) + .SetShortcut(Key.Delete); + + void SelectFace(Element element) + { + if (Context.ActiveUiDocument is null) return; + if (!element.IsValidObject) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetElementIds([element.Id])); + } + + void ShowFace(Element element) + { + if (Context.ActiveUiDocument is null) return; + if (!element.IsValidObject) return; + + RevitShell.ActionEventHandler.Raise(_ => + { + Context.ActiveUiDocument.ShowElements(element); + Context.ActiveUiDocument.Selection.SetElementIds([element.Id]); + }); + } + + async Task DeleteElement(Element element) + { + if (Context.ActiveUiDocument is null) return; + + ICollection? removedIds = []; + var notificationService = serviceProvider.GetRequiredService(); + try + { + await RevitShell.AsyncEventHandler.RaiseAsync(_ => + { + using var transaction = new Transaction(element.Document); + transaction.Start($"Delete {element.Name}"); + + try + { + removedIds = element.Document.Delete(element.Id); + transaction.Commit(); + + if (transaction.GetStatus() == TransactionStatus.RolledBack) throw new OperationCanceledException("Element deletion cancelled by user"); + } + catch + { + if (!transaction.HasEnded()) transaction.RollBack(); + throw; + } + }); + + var summaryViewModel = serviceProvider.GetRequiredService(); + var placementTarget = (FrameworkElement) contextMenu.PlacementTarget; + summaryViewModel.RemoveItem(placementTarget.DataContext); + + notificationService.ShowSuccess("Success", $"{removedIds.Count} elements completely removed from the Revit database"); + } + catch (OperationCanceledException exception) + { + notificationService.ShowWarning("Warning", exception.Message); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + + logger.LogError(exception, "Element deletion error"); + notificationService.ShowError("Element deletion error", exception.Message); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ElementIdDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ElementIdDescriptor.cs new file mode 100644 index 000000000..fbe0c15d5 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ElementIdDescriptor.cs @@ -0,0 +1,63 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ElementIdDescriptor : Descriptor, IDescriptorRedirector +{ + private readonly ElementId _elementId; + + public ElementIdDescriptor(ElementId elementId) + { + _elementId = elementId; + Name = _elementId.ToString(); + } + + public bool TryRedirect(string target, Document context, out object result) + { + result = _elementId; + if (target == nameof(Element.Id)) return false; + if (_elementId == ElementId.InvalidElementId) return false; + +#if REVIT2024_OR_GREATER + if (_elementId.Value is > -3000000 and < -2000000) +#else + if (_elementId.IntegerValue is > -3000000 and < -2000000) +#endif + { + var element = Category.GetCategory(context, _elementId); + if (element is null) return false; + + result = element; + return true; + } + else + { + var element = _elementId.ToElement(context); + if (element is null) return false; + + result = element; + return true; + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ElevationMarkerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ElevationMarkerDescriptor.cs new file mode 100644 index 000000000..6bb781567 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ElevationMarkerDescriptor.cs @@ -0,0 +1,70 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ElevationMarkerDescriptor(ElevationMarker elevationMarker) : ElementDescriptor(elevationMarker) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ElevationMarker.IsAvailableIndex) => ResolveIndex, + nameof(ElevationMarker.GetViewId) => ResolveViewId, + _ => null + }; + + IVariant ResolveIndex() + { + var variants = Variants.Values(elevationMarker.MaximumViewCount); + for (var i = 0; i < elevationMarker.MaximumViewCount; i++) + { + var result = elevationMarker.IsAvailableIndex(i); + variants.Add(result, $"Index {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveViewId() + { + var variants = Variants.Values(elevationMarker.MaximumViewCount); + for (var i = 0; i < elevationMarker.MaximumViewCount; i++) + { + if (elevationMarker.IsAvailableIndex(i)) continue; + + var result = elevationMarker.GetViewId(i); + var element = result.ToElement(elevationMarker.Document); + var name = element!.Name == string.Empty ? $"ID{element.Id}" : $"{element.Name}, ID{element.Id}"; + variants.Add(result, $"Index {i}: {name}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/EntityDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/EntityDescriptor.cs new file mode 100644 index 000000000..b3ef66563 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/EntityDescriptor.cs @@ -0,0 +1,108 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.ExtensibleStorage; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class EntityDescriptor(Entity entity) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Entity.Get) when parameters.Length == 1 && + parameters[0].ParameterType == typeof(string) => ResolveGetByField, + nameof(Entity.Get) when parameters.Length == 2 && + parameters[0].ParameterType == typeof(string) && + parameters[1].ParameterType == typeof(ForgeTypeId) => ResolveGetByFieldForge, + _ => null + }; + + IVariant ResolveGetByField() + { + var fields = entity.Schema.ListFields(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var method = entity.GetType().GetMethod(nameof(Entity.Get), [typeof(Field)])!; + var genericMethod = MakeGenericInvoker(field, method); + variants.Add(genericMethod.Invoke(entity, [field]), field.FieldName); + } + + return variants.Consume(); + } + + IVariant ResolveGetByFieldForge() + { + var fields = entity.Schema.ListFields(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var forgeTypeId = field.GetSpecTypeId(); + var unit = GetValidUnit(forgeTypeId); + var method = entity.GetType().GetMethod(nameof(Entity.Get), [typeof(Field), typeof(ForgeTypeId)])!; + var genericMethod = MakeGenericInvoker(field, method); + variants.Add(genericMethod.Invoke(entity, [field, unit]), field.FieldName); + } + + return variants.Consume(); + } + } + + private static ForgeTypeId GetValidUnit(ForgeTypeId forgeTypeId) + { +#if REVIT2022_OR_GREATER + var isMeasurableSpec = UnitUtils.IsMeasurableSpec(forgeTypeId); +#else + var isMeasurableSpec = false; + try + { + if (UnitUtils.IsSpec(forgeTypeId)) + { + UnitUtils.GetValidUnits(forgeTypeId); + isMeasurableSpec = true; + } + } + catch + { + // ignored + } +#endif + + return isMeasurableSpec ? UnitUtils.GetValidUnits(forgeTypeId).First() : UnitTypeId.Custom; + } + + private static MethodInfo MakeGenericInvoker(Field field, MethodInfo invoker) + { + var containerType = field.ContainerType switch + { + ContainerType.Simple => field.ValueType, + ContainerType.Array => typeof(IList<>).MakeGenericType(field.ValueType), + ContainerType.Map => typeof(IDictionary<,>).MakeGenericType(field.KeyType, field.ValueType), + _ => throw new ArgumentOutOfRangeException() + }; + + return invoker.MakeGenericMethod(containerType); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/EnumerableDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/EnumerableDescriptor.cs new file mode 100644 index 000000000..d74094703 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/EnumerableDescriptor.cs @@ -0,0 +1,83 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using System.Reflection; +using Autodesk.Revit.DB.Electrical; +using Autodesk.Revit.DB.Macros; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class EnumerableDescriptor : Descriptor, IDescriptorEnumerator, IDescriptorResolver +{ + public EnumerableDescriptor(IEnumerable value) + { + // SnoopUtils.ParseEnumerable dispose this Enumerator; + // ReSharper disable once GenericEnumeratorNotDisposed + Enumerator = value.GetEnumerator(); + + //Checking types to reduce memory allocation when creating an iterator and increase performance + IsEmpty = value switch + { + string => true, + ICollection enumerable => enumerable.Count == 0, + ParameterSet enumerable => enumerable.IsEmpty, + ParameterMap enumerable => enumerable.IsEmpty, + DefinitionBindingMap enumerable => enumerable.IsEmpty, + CategoryNameMap enumerable => enumerable.IsEmpty, + DefinitionGroups enumerable => enumerable.IsEmpty, + HashSet enumerable => enumerable.Count == 0, + HashSet enumerable => enumerable.Count == 0, + DocumentSet enumerable => enumerable.IsEmpty, + PhaseArray enumerable => enumerable.IsEmpty, + ProjectLocationSet enumerable => enumerable.IsEmpty, + PlanTopologySet enumerable => enumerable.IsEmpty, + CitySet enumerable => enumerable.IsEmpty, + WireTypeSet enumerable => enumerable.IsEmpty, + PanelTypeSet enumerable => enumerable.IsEmpty, + FamilyTypeSet enumerable => enumerable.IsEmpty, + MullionTypeSet enumerable => enumerable.IsEmpty, + VoltageTypeSet enumerable => enumerable.IsEmpty, + InsulationTypeSet enumerable => enumerable.IsEmpty, + TemperatureRatingTypeSet enumerable => enumerable.IsEmpty, + MacroManager enumerable => enumerable.Count == 0, + _ => !Enumerator.MoveNext() + }; + } + + public IEnumerator Enumerator { get; } + public bool IsEmpty { get; } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(IEnumerable.GetEnumerator) => ResolveGetEnumerator, + _ => null + }; + + IVariant ResolveGetEnumerator() + { + return Variants.Empty(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/EnumeratorDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/EnumeratorDescriptor.cs new file mode 100644 index 000000000..0ecebcaba --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/EnumeratorDescriptor.cs @@ -0,0 +1,56 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class EnumeratorDescriptor : Descriptor, IDescriptorRedirector +{ + private readonly object? _object; + private readonly IEnumerator _enumerator; + + public EnumeratorDescriptor(IEnumerator enumerator) + { + _enumerator = enumerator; + try + { + _object = enumerator.Current; + } + catch + { + // ignored + } + } + + public bool TryRedirect(string target, out object result) + { + if (_object is null) + { + result = _enumerator; + return false; + } + + result = _object; + return true; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/EvaluatedParameterDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/EvaluatedParameterDescriptor.cs new file mode 100644 index 000000000..9cb8e3991 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/EvaluatedParameterDescriptor.cs @@ -0,0 +1,58 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +#if REVIT2024_OR_GREATER +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class EvaluatedParameterDescriptor : Descriptor, IDescriptorResolver +{ + private readonly EvaluatedParameter _parameter; + + public EvaluatedParameterDescriptor(EvaluatedParameter parameter) + { + _parameter = parameter; + Name = parameter.Definition.Name; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(EvaluatedParameter.AsValueString) when parameters!.Length == 1 => ResolveAsValueString, + nameof(EvaluatedParameter.AsValueString) when parameters.Length == 2 => ResolveAsValueStringFormat, + _ => null + }; + + IVariant ResolveAsValueString(Document context) + { + return Variants.Value(_parameter.AsValueString(context)); + } + + IVariant ResolveAsValueStringFormat(Document context) + { + return Variants.Value(_parameter.AsValueString(context, new FormatOptions())); + } + } +} +#endif \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ExternalServiceDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ExternalServiceDescriptor.cs new file mode 100644 index 000000000..47ba6ca2b --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ExternalServiceDescriptor.cs @@ -0,0 +1,58 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.ExternalService; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ExternalServiceDescriptor : Descriptor, IDescriptorResolver +{ + private readonly ExternalService _service; + + public ExternalServiceDescriptor(ExternalService service) + { + _service = service; + Name = service.Name; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ExternalService.GetServer) => ResolveGetServer, + _ => null + }; + + IVariant ResolveGetServer() + { + var serverIds = _service.GetRegisteredServerIds(); + var variants = Variants.Values(_service.NumberOfServers); + foreach (var serverId in serverIds) + { + variants.Add(_service.GetServer(serverId)); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FaceDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FaceDescriptor.cs new file mode 100644 index 000000000..d80ab564a --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FaceDescriptor.cs @@ -0,0 +1,108 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public class FaceDescriptor : Descriptor, IDescriptorCollector, IContextMenuConnector +{ + private readonly Face _face; + + public FaceDescriptor(Face face) + { + _face = face; + Name = $"{face.Area.ToString(CultureInfo.InvariantCulture)} ft²"; + } + + public virtual void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { +#if REVIT2023_OR_GREATER + + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_face, SelectFace) + .SetShortcut(Key.F6); + + contextMenu.AddMenuItem("ShowMenuItem") + .SetCommand(_face, ShowFace) + .SetShortcut(Key.F7); +#endif + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability(_face.Area > 1e-6) + .SetCommand(_face, VisualizeFace) + .SetShortcut(Key.F8); + + async Task VisualizeFace(Face face) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(face); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize Face error"); + notificationService.ShowError("Visualization error", exception); + } + } +#if REVIT2023_OR_GREATER + + void SelectFace(Face face) + { + if (Context.ActiveUiDocument is null) return; + if (face.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetReferences([face.Reference])); + } + + void ShowFace(Face face) + { + if (Context.ActiveUiDocument is null) return; + if (face.Reference is null) return; + + RevitShell.ActionEventHandler.Raise(application => + { + var uiDocument = application.ActiveUIDocument; + if (uiDocument is null) return; + + var element = face.Reference.ElementId.ToElement(uiDocument.Document); + if (element is not null) uiDocument.ShowElements(element); + + uiDocument.Selection.SetReferences([face.Reference]); + }); + } +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Views/Pages/AboutPage.xaml.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FailureMessageDescriptor.cs similarity index 73% rename from source/RevitLookup/Views/Pages/AboutPage.xaml.cs rename to source/RevitLookup/Core/Decomposition/Descriptors/FailureMessageDescriptor.cs index 511defcc6..ce9318ee8 100644 --- a/source/RevitLookup/Views/Pages/AboutPage.xaml.cs +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FailureMessageDescriptor.cs @@ -18,19 +18,15 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using RevitLookup.ViewModels.Pages; -using Wpf.Ui.Controls; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; -namespace RevitLookup.Views.Pages; +namespace RevitLookup.Core.Decomposition.Descriptors; -public sealed partial class AboutPage : INavigableView +public sealed class FailureMessageDescriptor : Descriptor, IDescriptorCollector { - public AboutPage(AboutViewModel viewModel) + public FailureMessageDescriptor(FailureMessage message) { - ViewModel = viewModel; - InitializeComponent(); - DataContext = this; + Name = message.GetDescriptionText(); } - - public AboutViewModel ViewModel { get; } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilyDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyDescriptor.cs new file mode 100644 index 000000000..3854c0ef7 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyDescriptor.cs @@ -0,0 +1,66 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilyDescriptor(Family family) : ElementDescriptor(family) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return null; + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(FamilySizeTableManager.GetFamilySizeTableManager), RegisterGetFamilySizeTableManager); + manager.Register(nameof(FamilyUtils.FamilyCanConvertToFaceHostBased), RegisterFamilyCanConvertToFaceHostBased); + manager.Register(nameof(FamilyUtils.GetProfileSymbols), RegisterProfileSymbols); + return; + + IVariant RegisterGetFamilySizeTableManager() + { + return Variants.Value(FamilySizeTableManager.GetFamilySizeTableManager(family.Document, family.Id)); + } + + IVariant RegisterFamilyCanConvertToFaceHostBased() + { + return Variants.Value(FamilyUtils.FamilyCanConvertToFaceHostBased(family.Document, family.Id)); + } + + IVariant RegisterProfileSymbols() + { + var values = Enum.GetValues(typeof(ProfileFamilyUsage)); + var capacity = values.Length * 2; + var variants = Variants.Values>(capacity); + + foreach (ProfileFamilyUsage value in values) + { + variants.Add(FamilyUtils.GetProfileSymbols(family.Document, value, false), $"{value}, with multiple curve loops"); + variants.Add(FamilyUtils.GetProfileSymbols(family.Document, value, true), $"{value}, with single curve loop"); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilyInstanceDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyInstanceDescriptor.cs new file mode 100644 index 000000000..db3c15cd9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyInstanceDescriptor.cs @@ -0,0 +1,155 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Architecture; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilyInstanceDescriptor(FamilyInstance familyInstance) : ElementDescriptor(familyInstance) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + "Room" when parameters.Length == 1 => ResolveGetRoom, + "FromRoom" when parameters.Length == 1 => ResolveFromRoom, + "ToRoom" when parameters.Length == 1 => ResolveToRoom, + nameof(FamilyInstance.GetOriginalGeometry) => ResolveOriginalGeometry, + nameof(FamilyInstance.GetReferences) => ResolveGetReferences, + _ => null + }; + + IVariant ResolveGetRoom() + { + var variants = Variants.Values(familyInstance.Document.Phases.Size); + foreach (Phase phase in familyInstance.Document.Phases) + { + if (familyInstance.GetPhaseStatus(phase.Id) == ElementOnPhaseStatus.Future) continue; + variants.Add(familyInstance.get_Room(phase), phase.Name); + } + + return variants.Consume(); + } + + IVariant ResolveFromRoom() + { + var variants = Variants.Values(familyInstance.Document.Phases.Size); + foreach (Phase phase in familyInstance.Document.Phases) + { + if (familyInstance.GetPhaseStatus(phase.Id) == ElementOnPhaseStatus.Future) continue; + variants.Add(familyInstance.get_FromRoom(phase), phase.Name); + } + + return variants.Consume(); + } + + IVariant ResolveToRoom() + { + var variants = Variants.Values(familyInstance.Document.Phases.Size); + foreach (Phase phase in familyInstance.Document.Phases) + { + if (familyInstance.GetPhaseStatus(phase.Id) == ElementOnPhaseStatus.Future) continue; + variants.Add(familyInstance.get_ToRoom(phase), phase.Name); + } + + return variants.Consume(); + } + + IVariant ResolveOriginalGeometry() + { + return Variants.Values(10) + .Add(familyInstance.GetOriginalGeometry(new Options + { + View = Context.ActiveView, + }), "Active view") + .Add(familyInstance.GetOriginalGeometry(new Options + { + View = Context.ActiveView, + IncludeNonVisibleObjects = true, + }), "Active view, including non-visible objects") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Coarse, + }), "Model, coarse detail level") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Fine, + }), "Model, fine detail level") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Medium, + }), "Model, medium detail level") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Undefined, + }), "Model, undefined detail level") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Coarse, + IncludeNonVisibleObjects = true, + }), "Model, coarse detail level, including non-visible objects") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Fine, + IncludeNonVisibleObjects = true, + }), "Model, fine detail level, including non-visible objects") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Medium, + IncludeNonVisibleObjects = true, + }), "Model, medium detail level, including non-visible objects") + .Add(familyInstance.GetOriginalGeometry(new Options + { + DetailLevel = ViewDetailLevel.Undefined, + IncludeNonVisibleObjects = true, + }), "Model, undefined detail level, including non-visible objects") + .Consume(); + } + + IVariant ResolveGetReferences() + { + return Variants.Values>(11) + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Back), "Back") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Bottom), "Bottom") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.StrongReference), "Strong reference") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.WeakReference), "Weak reference") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Front), "Front") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Left), "Left") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Right), "Right") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.Top), "Top") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.CenterElevation), "Center elevation") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.CenterFrontBack), "Center front back") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.CenterLeftRight), "Center left right") + .Add(familyInstance.GetReferences(FamilyInstanceReferenceType.NotAReference), "Not a reference") + .Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds), + () => Variants.Value(AdaptiveComponentInstanceUtils.GetInstancePlacementPointElementRefIds(familyInstance))); + manager.Register(nameof(AdaptiveComponentInstanceUtils.IsAdaptiveComponentInstance), + () => Variants.Value(AdaptiveComponentInstanceUtils.IsAdaptiveComponentInstance(familyInstance))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilyManagerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyManagerDescriptor.cs new file mode 100644 index 000000000..6e9baa7a8 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyManagerDescriptor.cs @@ -0,0 +1,97 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilyManagerDescriptor(FamilyManager familyManager) : Descriptor, IDescriptorResolver, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(FamilyManager.IsParameterLockable) => ResolveIsParameterLockable, + nameof(FamilyManager.IsParameterLocked) => ResolveIsParameterLocked, + _ => null + }; + + IVariant ResolveIsParameterLockable() + { + var familyParameters = familyManager.Parameters; + var variants = Variants.Values(familyParameters.Size); + foreach (FamilyParameter parameter in familyParameters) + { + var result = familyManager.IsParameterLockable(parameter); + variants.Add(result, $"{parameter.Definition.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsParameterLocked() + { + var familyParameters = familyManager.Parameters; + var variants = Variants.Values(familyParameters.Size); + foreach (FamilyParameter parameter in familyParameters) + { + var result = familyManager.IsParameterLocked(parameter); + variants.Add(result, $"{parameter.Definition.Name}: {result}"); + } + + return variants.Consume(); + } + } + + Func? IDescriptorResolver.Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(FamilyManager.GetAssociatedFamilyParameter) => ResolveGetAssociatedFamilyParameter, + _ => null + }; + + IVariant ResolveGetAssociatedFamilyParameter(Document context) + { + var elementTypes = context.GetElements().WhereElementIsElementType(); + var elementInstances = context.GetElements().WhereElementIsNotElementType(); + var elements = elementTypes + .UnionWith(elementInstances) + .ToElements(); + + var variants = Variants.Values>(elements.Count); + foreach (var element in elements) + { + foreach (Parameter parameter in element.Parameters) + { + var familyParameter = familyManager.GetAssociatedFamilyParameter(parameter); + if (familyParameter is not null) + { + variants.Add(new KeyValuePair(parameter, familyParameter)); + } + } + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilyParameterDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyParameterDescriptor.cs new file mode 100644 index 000000000..4dc2d16dc --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilyParameterDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilyParameterDescriptor : Descriptor, IDescriptorCollector +{ + public FamilyParameterDescriptor(FamilyParameter familyParameter) + { + Name = familyParameter.Definition.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableColumnDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableColumnDescriptor.cs new file mode 100644 index 000000000..5fdcc6a3f --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableColumnDescriptor.cs @@ -0,0 +1,31 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilySizeTableColumnDescriptor : Descriptor +{ + public FamilySizeTableColumnDescriptor(FamilySizeTableColumn column) + { + Name = column.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableDescriptor.cs new file mode 100644 index 000000000..b38ca424b --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableDescriptor.cs @@ -0,0 +1,89 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilySizeTableDescriptor(FamilySizeTable table) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(FamilySizeTable.GetColumnHeader) => ResolveColumnHeader, + nameof(FamilySizeTable.IsValidColumnIndex) => ResolveIsValidColumnIndex, + _ => null + }; + + IVariant ResolveColumnHeader() + { + var count = table.NumberOfColumns; + var variants = Variants.Values(count); + + for (var i = 0; i < count; i++) + { + variants.Add(table.GetColumnHeader(i)); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidColumnIndex() + { + var count = table.NumberOfColumns; + var variants = Variants.Values(count); + + for (var i = 0; i <= count; i++) + { + var result = table.IsValidColumnIndex(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + } + + // TODO: rework FamilySizeTableEditDialog + // public void RegisterMenu(ContextMenu contextMenu) + // { + // var context = (ISnoopViewModel) contextMenu.DataContext; + // var document = context.SnoopableObjects[0].Context; + // + // contextMenu.AddMenuItem("ShowMenuItem") + // .SetHeader("Show table") + // .SetAvailability(table.IsValidObject) + // .SetCommand(table, async sizeTable => + // { + // try + // { + // var dialog = new FamilySizeTableEditDialog(document, sizeTable); + // await dialog.ShowAsync(); + // } + // catch (Exception exception) + // { + // var logger = context.ServiceProvider.GetRequiredService>(); + // logger.LogError(exception, "FamilySizeTableDialog error"); + // } + // }); + // } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableManagerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableManagerDescriptor.cs new file mode 100644 index 000000000..2db568e66 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FamilySizeTableManagerDescriptor.cs @@ -0,0 +1,112 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FamilySizeTableManagerDescriptor(FamilySizeTableManager manager) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(FamilySizeTableManager.GetSizeTable) => ResolveSizeTable, + nameof(FamilySizeTableManager.HasSizeTable) => ResolveHasSizeTable, + nameof(FamilySizeTableManager.GetFamilySizeTableManager) => ResolveGetFamilySizeTableManager, + _ => null + }; + + IVariant ResolveSizeTable() + { + var names = manager.GetAllSizeTableNames(); + var variants = Variants.Values(names.Count); + + foreach (var name in names) + { + variants.Add(manager.GetSizeTable(name), name); + } + + return variants.Consume(); + } + + IVariant ResolveHasSizeTable() + { + var names = manager.GetAllSizeTableNames(); + var variants = Variants.Values(names.Count); + + foreach (var name in names) + { + var result = manager.HasSizeTable(name); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetFamilySizeTableManager() + { + return Variants.Value(manager); + } + } + + // TODO: rework FamilySizeTableSelectDialog + // public void RegisterMenu(ContextMenu contextMenu) + // { + // var context = (ISnoopViewModel) contextMenu.DataContext; + // var document = context.SnoopableObjects[0].Context; + // + // contextMenu.AddMenuItem("ExportMenuItem") + // .SetHeader("Export table") + // .SetAvailability(manager.GetAllSizeTableNames().Count > 0) + // .SetCommand(manager, async _ => + // { + // try + // { + // var dialog = new FamilySizeTableSelectDialog(context.ServiceProvider, document, manager); + // await dialog.ShowExportDialogAsync(); + // } + // catch (Exception exception) + // { + // var logger = context.ServiceProvider.GetRequiredService>(); + // logger.LogError(exception, "Initialize FamilySizeTableExportDialog error"); + // } + // }); + // + // contextMenu.AddMenuItem("EditMenuItem") + // .SetHeader("Edit table") + // .SetAvailability(document.IsFamilyDocument && manager.GetAllSizeTableNames().Count > 0) + // .SetCommand(manager, async _ => + // { + // try + // { + // var dialog = new FamilySizeTableSelectDialog(context.ServiceProvider, document, manager); + // await dialog.ShowEditDialogAsync(); + // } + // catch (Exception exception) + // { + // var logger = context.ServiceProvider.GetRequiredService>(); + // logger.LogError(exception, "Initialize FamilySizeTableSelectDialog error"); + // } + // }); + // } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/FieldDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/FieldDescriptor.cs new file mode 100644 index 000000000..e5ddc5b86 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/FieldDescriptor.cs @@ -0,0 +1,33 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.ExtensibleStorage; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class FieldDescriptor : Descriptor, IDescriptorCollector +{ + public FieldDescriptor(Field field) + { + Name = field.FieldName; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ForgeTypeIdDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ForgeTypeIdDescriptor.cs new file mode 100644 index 000000000..2ddec4b19 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ForgeTypeIdDescriptor.cs @@ -0,0 +1,65 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ForgeTypeIdDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension +{ + private readonly ForgeTypeId _typeId; + + public ForgeTypeIdDescriptor(ForgeTypeId typeId) + { + _typeId = typeId; + Name = typeId.TypeId; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ForgeTypeId.Clear) when parameters.Length == 0 => Variants.Disabled, + _ => null + }; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("ToUnitLabel", () => Variants.Value(_typeId.ToUnitLabel())); + manager.Register("ToSpecLabel", () => Variants.Value(_typeId.ToSpecLabel())); + manager.Register("ToSymbolLabel", () => Variants.Value(_typeId.ToSymbolLabel())); +#if REVIT2022_OR_GREATER + manager.Register("ToGroupLabel", () => Variants.Value(_typeId.ToGroupLabel())); + manager.Register("ToDisciplineLabel", () => Variants.Value(_typeId.ToDisciplineLabel())); + manager.Register("ToParameterLabel", () => Variants.Value(_typeId.ToParameterLabel())); +#endif + manager.Register("IsUnit", () => Variants.Value(UnitUtils.IsUnit(_typeId))); + manager.Register("IsSymbol", () => Variants.Value(UnitUtils.IsSymbol(_typeId))); +#if REVIT2022_OR_GREATER + manager.Register("IsSpec", () => Variants.Value(SpecUtils.IsSpec(_typeId))); + manager.Register("IsMeasurableSpec", () => Variants.Value(UnitUtils.IsMeasurableSpec(_typeId))); + manager.Register("IsBuiltInParameter", () => Variants.Value(ParameterUtils.IsBuiltInParameter(_typeId))); + manager.Register("IsBuiltInGroup", () => Variants.Value(ParameterUtils.IsBuiltInGroup(_typeId))); +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/GuidEnumDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/GuidEnumDescriptor.cs new file mode 100644 index 000000000..6f0fe9791 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/GuidEnumDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class GuidEnumDescriptor : Descriptor, IDescriptorCollector +{ + public GuidEnumDescriptor(GuidEnum guidEnum) + { + Name = guidEnum.Guid.ToString(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/HostObjectDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/HostObjectDescriptor.cs new file mode 100644 index 000000000..276d6c78f --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/HostObjectDescriptor.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class HostObjectDescriptor(HostObject hostObject) : ElementDescriptor(hostObject) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(HostObject.FindInserts) => ResolveFindInserts, + _ => null + }; + + IVariant ResolveFindInserts() + { + return Variants.Value(hostObject.FindInserts(true, true, true, true)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(HostExtensions.GetBottomFaces), () => Variants.Value(hostObject.GetBottomFaces())); + manager.Register(nameof(HostExtensions.GetTopFaces), () => Variants.Value(hostObject.GetTopFaces())); + manager.Register(nameof(HostExtensions.GetSideFaces), () => Variants.Values>(2) + .Add(hostObject.GetSideFaces(ShellLayerType.Interior), "Interior") + .Add(hostObject.GetSideFaces(ShellLayerType.Exterior), "Exterior") + .Consume()); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/IndependentTagDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/IndependentTagDescriptor.cs new file mode 100644 index 000000000..a8ade8d70 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/IndependentTagDescriptor.cs @@ -0,0 +1,132 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Structure; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class IndependentTagDescriptor(IndependentTag tag) : ElementDescriptor(tag) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { +#if REVIT2025_OR_GREATER //TODO Fatal https://github.com/jeremytammik/RevitLookup/issues/225 + nameof(IndependentTag.TagText) when RebarBendingDetail.IsBendingDetail(tag) => Variants.Disabled, +#endif + nameof(IndependentTag.CanLeaderEndConditionBeAssigned) => ResolveLeaderEndCondition, +#if REVIT2022_OR_GREATER + nameof(IndependentTag.GetLeaderElbow) => ResolveLeaderElbow, + nameof(IndependentTag.GetLeaderEnd) => ResolveLeaderEnd, + nameof(IndependentTag.HasLeaderElbow) => ResolveHasLeaderElbow, +#endif +#if REVIT2023_OR_GREATER + nameof(IndependentTag.IsLeaderVisible) => ResolveIsLeaderVisible, +#endif + _ => null + }; + + IVariant ResolveLeaderEndCondition() + { + var conditions = Enum.GetValues(typeof(LeaderEndCondition)); + var variants = Variants.Values(conditions.Length); + + foreach (LeaderEndCondition condition in conditions) + { + var result = tag.CanLeaderEndConditionBeAssigned(condition); + variants.Add(result, $"{condition}: {result}"); + } + + return variants.Consume(); + } +#if REVIT2022_OR_GREATER + IVariant ResolveLeaderElbow() + { + var references = tag.GetTaggedReferences(); + var variants = Variants.Values(references.Count); + + foreach (var reference in references) + { +#if REVIT2023_OR_GREATER + if (!tag.IsLeaderVisible(reference)) continue; +#endif + if (!tag.HasLeaderElbow(reference)) continue; + + variants.Add(tag.GetLeaderElbow(reference)); + } + + return variants.Consume(); + } + + IVariant ResolveLeaderEnd() + { + var references = tag.GetTaggedReferences(); + var variants = Variants.Values(references.Count); + + foreach (var reference in references) + { +#if REVIT2023_OR_GREATER + if (!tag.IsLeaderVisible(reference)) continue; +#endif + variants.Add(tag.GetLeaderEnd(reference)); + } + + return variants.Consume(); + } + + IVariant ResolveHasLeaderElbow() + { + var references = tag.GetTaggedReferences(); + var variants = Variants.Values(references.Count); + foreach (var reference in references) + { +#if REVIT2023_OR_GREATER + if (!tag.IsLeaderVisible(reference)) continue; +#endif + variants.Add(tag.HasLeaderElbow(reference)); + } + + return variants.Consume(); + } +#endif +#if REVIT2023_OR_GREATER + + IVariant ResolveIsLeaderVisible() + { + var references = tag.GetTaggedReferences(); + var variants = Variants.Values(references.Count); + + foreach (var reference in references) + { + variants.Add(tag.IsLeaderVisible(reference)); + } + + return variants.Consume(); + } +#endif + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/InternalOriginDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/InternalOriginDescriptor.cs new file mode 100644 index 000000000..aa74248c2 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/InternalOriginDescriptor.cs @@ -0,0 +1,46 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class InternalOriginDescriptor(InternalOrigin internalOrigin) : ElementDescriptor(internalOrigin) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(InternalOrigin.Get) => ResolveGet, + _ => null + }; + + IVariant ResolveGet() + { + return Variants.Value(InternalOrigin.Get(internalOrigin.Document)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/LightFamilyDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/LightFamilyDescriptor.cs new file mode 100644 index 000000000..35b59abc7 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/LightFamilyDescriptor.cs @@ -0,0 +1,65 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Lighting; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class LightFamilyDescriptor(LightFamily lightFamily) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(LightFamily.GetLightTypeName) => ResolveLightTypeName, + nameof(LightFamily.GetLightType) => ResolveLightType, + _ => null + }; + + IVariant ResolveLightTypeName() + { + var capacity = lightFamily.GetNumberOfLightTypes(); + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var name = lightFamily.GetLightTypeName(i); + variants.Add(name); + } + + return variants.Consume(); + } + + IVariant ResolveLightType() + { + var capacity = lightFamily.GetNumberOfLightTypes(); + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var type = lightFamily.GetLightType(i); + variants.Add(type, $"Index {i}"); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/LocationCurveDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/LocationCurveDescriptor.cs new file mode 100644 index 000000000..0a96a460d --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/LocationCurveDescriptor.cs @@ -0,0 +1,62 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class LocationCurveDescriptor(LocationCurve locationCurve) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + "ElementsAtJoin" => ResolveElementsAtJoin, + "JoinType" => ResolveJoinType, + _ => null + }; + + IVariant ResolveElementsAtJoin() + { + var variants = Variants.Values(2); + for (var i = 0; i < 2; i++) + { + var elements = locationCurve.get_ElementsAtJoin(i); + variants.Add(elements, $"Point {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveJoinType() + { + var variants = Variants.Values(2); + for (var i = 0; i < 2; i++) + { + var joinType = locationCurve.get_JoinType(i); + variants.Add(joinType, $"Point {i}"); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/MepSectionDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/MepSectionDescriptor.cs new file mode 100644 index 000000000..e086db338 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/MepSectionDescriptor.cs @@ -0,0 +1,119 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Mechanical; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using ArgumentException = Autodesk.Revit.Exceptions.ArgumentException; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class MepSectionDescriptor(MEPSection mepSection) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(MEPSection.GetElementIds) => ResolveSectionIds, + nameof(MEPSection.GetCoefficient) => ResolveCoefficient, + nameof(MEPSection.GetPressureDrop) => ResolvePressureDrop, + nameof(MEPSection.GetSegmentLength) => ResolveSegmentLength, + nameof(MEPSection.IsMain) => ResolveIsMain, + _ => null + }; + + IVariant ResolveSectionIds() + { + var elementIds = mepSection.GetElementIds(); + var variants = Variants.Values(elementIds.Count); + foreach (var id in elementIds) + { + variants.Add(id); + } + + return variants.Consume(); + } + + IVariant ResolveCoefficient() + { + var elementIds = mepSection.GetElementIds(); + var variants = Variants.Values(elementIds.Count); + foreach (var id in elementIds) + { + variants.Add(mepSection.GetCoefficient(id), $"ID{id}"); + } + + return variants.Consume(); + } + + IVariant ResolvePressureDrop() + { + var elementIds = mepSection.GetElementIds(); + var variants = Variants.Values(elementIds.Count); + foreach (var id in elementIds) + { + variants.Add(mepSection.GetPressureDrop(id), $"ID{id}"); + } + + return variants.Consume(); + } + + IVariant ResolveSegmentLength() + { + var elementIds = mepSection.GetElementIds(); + var variants = Variants.Values(elementIds.Count); + foreach (var id in elementIds) + { + try + { + var length = mepSection.GetSegmentLength(id); + variants.Add(length, $"ID{id}"); + } + catch (ArgumentException) + { + // ignored + } + } + + return variants.Consume(); + } + + IVariant ResolveIsMain() + { + var elementIds = mepSection.GetElementIds(); + var variants = Variants.Values(elementIds.Count); + foreach (var id in elementIds) + { + try + { + var isMain = mepSection.IsMain(id); + variants.Add(isMain, $"ID{id}"); + } + catch (ArgumentException) + { + // ignored + } + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/MepSystemDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/MepSystemDescriptor.cs new file mode 100644 index 000000000..ac098c655 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/MepSystemDescriptor.cs @@ -0,0 +1,69 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Mechanical; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class MepSystemDescriptor(MEPSystem mepSystem) : ElementDescriptor(mepSystem) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(MEPSystem.GetSectionByIndex) => ResolveSectionByIndex, + nameof(MEPSystem.GetSectionByNumber) => ResolveSectionByNumber, + _ => null + }; + + IVariant ResolveSectionByNumber() + { + var capacity = mepSystem.SectionsCount; + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var section = mepSystem.GetSectionByIndex(i); + variants.Add(section, $"Number {section.Number}"); + } + + return variants.Consume(); + } + + IVariant ResolveSectionByIndex() + { + var capacity = mepSystem.SectionsCount; + var variants = Variants.Values(capacity); + for (var i = 0; i < capacity; i++) + { + var section = mepSystem.GetSectionByIndex(i); + variants.Add(section, $"Index {i}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/MeshDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/MeshDescriptor.cs new file mode 100644 index 000000000..1bf720d94 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/MeshDescriptor.cs @@ -0,0 +1,62 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class MeshDescriptor(Mesh mesh) : Descriptor, IDescriptorCollector, IContextMenuConnector +{ + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability(mesh.Vertices.Count > 0) + .SetCommand(mesh, VisualizeMesh) + .SetShortcut(Key.F8); + + async Task VisualizeMesh(Mesh meshParameter) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(meshParameter); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize Mesh error"); + notificationService.ShowError("Visualization error", exception); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PanelDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PanelDescriptor.cs new file mode 100644 index 000000000..bc8396953 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PanelDescriptor.cs @@ -0,0 +1,53 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PanelDescriptor(Panel panel) : ElementDescriptor(panel) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Panel.GetRefGridLines) => ResolveGridLines, + _ => null + }; + + IVariant ResolveGridLines() + { + ElementId? uId = null; + ElementId? vId = null; + panel.GetRefGridLines(ref uId, ref vId); + + return Variants.Values(2) + .Add(uId) + .Add(vId) + .Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PaperSize.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PaperSize.cs new file mode 100644 index 000000000..9c9d93667 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PaperSize.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PaperSizeDescriptor : Descriptor, IDescriptorCollector +{ + public PaperSizeDescriptor(PaperSize paperSize) + { + Name = paperSize.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ParameterDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ParameterDescriptor.cs new file mode 100644 index 000000000..cb29ac8a0 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ParameterDescriptor.cs @@ -0,0 +1,111 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.EditDialogs; +using Wpf.Ui.Controls; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ParameterDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension, IContextMenuConnector +{ + private readonly Parameter _parameter; + + public ParameterDescriptor(Parameter parameter) + { + _parameter = parameter; + Name = parameter.Definition.Name; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Parameter.ClearValue) => Variants.Disabled, + _ => null + }; + } + + public void RegisterExtensions(IExtensionManager manager) + { + if (_parameter.StorageType == StorageType.Integer) + { + manager.Register(nameof(ParameterExtensions.AsBool), () => Variants.Value(_parameter.AsBool())); + manager.Register(nameof(ParameterExtensions.AsColor), () => Variants.Value(_parameter.AsColor())); + } + + if (_parameter.Element.Document.IsFamilyDocument) + { + manager.Register(nameof(FamilyManager.GetAssociatedFamilyParameter), RegisterGetAssociatedFamilyParameter); + } + + return; + + IVariant RegisterGetAssociatedFamilyParameter() + { + return Variants.Value(_parameter.Element.Document.FamilyManager.GetAssociatedFamilyParameter(_parameter)); + } + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("EditMenuItem") + .SetHeader("Edit value") + .SetAvailability(!_parameter.IsReadOnly && _parameter.StorageType != StorageType.None) + .SetCommand(_parameter, EditParameter) + .SetShortcut(Key.F2); + + return; + + async Task EditParameter(Parameter parameter) + { + try + { + var dialog = serviceProvider.GetRequiredService(); + var result = await dialog.ShowAsync(parameter.Definition.Name, RevitShell.GetParameterValue(parameter), "Update the parameter"); + if (result == ContentDialogResult.Primary) + { + await RevitShell.AsyncEventHandler.RaiseAsync(_ => RevitShell.UpdateParameterValue(parameter, dialog.Value)); + + var decompositionViewModel = serviceProvider.GetRequiredService(); + await decompositionViewModel.RefreshMembersAsync(); + } + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Update value error"); + notificationService.ShowError("Updating parameter value error", exception); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PartDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PartDescriptor.cs new file mode 100644 index 000000000..83ba6d1d9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PartDescriptor.cs @@ -0,0 +1,52 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PartDescriptor(Part part) : ElementDescriptor(part), IDescriptorExtension +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return null; + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(PartUtils.IsMergedPart), () => Variants.Value(PartUtils.IsMergedPart(part))); + manager.Register(nameof(PartUtils.IsPartDerivedFromLink), () => Variants.Value(PartUtils.IsPartDerivedFromLink(part))); + manager.Register(nameof(PartUtils.GetChainLengthToOriginal), () => Variants.Value(PartUtils.GetChainLengthToOriginal(part))); + manager.Register(nameof(PartUtils.GetMergedParts), () => Variants.Value(PartUtils.GetMergedParts(part))); + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(PartUtils.ArePartsValidForDivide), context => Variants.Value(PartUtils.ArePartsValidForDivide(context, [part.Id]))); + manager.Register(nameof(PartUtils.FindMergeableClusters), context => Variants.Value(PartUtils.FindMergeableClusters(context, [part.Id]))); + manager.Register(nameof(PartUtils.ArePartsValidForMerge), context => Variants.Value(PartUtils.ArePartsValidForMerge(context, [part.Id]))); + manager.Register(nameof(PartUtils.GetAssociatedPartMaker), context => Variants.Value(PartUtils.GetAssociatedPartMaker(context, part.Id))); + manager.Register(nameof(PartUtils.GetSplittingCurves), context => Variants.Value(PartUtils.GetSplittingCurves(context, part.Id))); + manager.Register(nameof(PartUtils.GetSplittingElements), context => Variants.Value(PartUtils.GetSplittingElements(context, part.Id))); + manager.Register(nameof(PartUtils.HasAssociatedParts), context => Variants.Value(PartUtils.HasAssociatedParts(context, part.Id))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PartMakerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PartMakerDescriptor.cs new file mode 100644 index 000000000..6bf4e14d2 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PartMakerDescriptor.cs @@ -0,0 +1,38 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PartMakerDescriptor(PartMaker partMaker) : ElementDescriptor(partMaker) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return null; + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(PartUtils.GetPartMakerMethodToDivideVolumeFW), () => Variants.Value(PartUtils.GetPartMakerMethodToDivideVolumeFW(partMaker))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PerformanceAdviserDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PerformanceAdviserDescriptor.cs new file mode 100644 index 000000000..8539b5289 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PerformanceAdviserDescriptor.cs @@ -0,0 +1,127 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PerformanceAdviserDescriptor(PerformanceAdviser adviser) : Descriptor, IDescriptorResolver, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(PerformanceAdviser.GetRuleDescription) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveGetRuleDescription, + nameof(PerformanceAdviser.GetRuleId) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveGetRuleId, + nameof(PerformanceAdviser.GetRuleName) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveGetRuleName, + nameof(PerformanceAdviser.IsRuleEnabled) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveIsRuleEnabled, + nameof(PerformanceAdviser.WillRuleCheckElements) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveWillRuleCheckElements, + nameof(PerformanceAdviser.GetElementFilterFromRule) when parameters!.Length == 2 && + parameters[0].ParameterType == typeof(int) => ResolveGetElementFilterFromRule, + _ => null + }; + + IVariant ResolveGetElementFilterFromRule() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) variants.Add(new KeyValuePair(i, adviser.GetElementFilterFromRule(i, Context.ActiveDocument))); + return variants.Consume(); + } + + IVariant ResolveWillRuleCheckElements() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) + { + variants.Add(new KeyValuePair(i, adviser.WillRuleCheckElements(i))); + } + + return variants.Consume(); + } + + IVariant ResolveIsRuleEnabled() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) + { + variants.Add(new KeyValuePair(i, adviser.IsRuleEnabled(i))); + } + + return variants.Consume(); + } + + IVariant ResolveGetRuleName() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) variants.Add(new KeyValuePair(i, adviser.GetRuleName(i))); + return variants.Consume(); + } + + IVariant ResolveGetRuleId() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) + { + variants.Add(new KeyValuePair(i, adviser.GetRuleId(i))); + } + + return variants.Consume(); + } + + IVariant ResolveGetRuleDescription() + { + var rules = adviser.GetNumberOfRules(); + var variants = Variants.Values>(rules); + for (var i = 0; i < rules; i++) + { + variants.Add(new KeyValuePair(i, adviser.GetRuleDescription(i))); + } + + return variants.Consume(); + } + } + + Func? IDescriptorResolver.Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(PerformanceAdviser.ExecuteAllRules) when parameters!.Length == 1 && + parameters[0].ParameterType == typeof(Document) => ResolveExecuteAllRules, + _ => null + }; + + IVariant ResolveExecuteAllRules(Document context) + { + return Variants.Value(adviser.ExecuteAllRules(context)); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PipeDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PipeDescriptor.cs new file mode 100644 index 000000000..a6b8f2eea --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PipeDescriptor.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Plumbing; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PipeDescriptor(Pipe pipe) : ElementDescriptor(pipe) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return null; + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(PlumbingUtils.PlaceCapOnOpenEnds), () => Variants.Value(PlumbingUtils.HasOpenConnector(pipe.Document, pipe.Id))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PlanViewRangeDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PlanViewRangeDescriptor.cs new file mode 100644 index 000000000..497aa8017 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PlanViewRangeDescriptor.cs @@ -0,0 +1,58 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PlanViewRangeDescriptor(PlanViewRange viewRange) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(PlanViewRange.GetOffset) => ResolveGetOffset, + nameof(PlanViewRange.GetLevelId) => ResolveGetLevelId, + _ => null + }; + + IVariant ResolveGetOffset() + { + return Variants.Values(4) + .Add(viewRange.GetOffset(PlanViewPlane.TopClipPlane), "Top clip plane") + .Add(viewRange.GetOffset(PlanViewPlane.CutPlane), "Cut plane") + .Add(viewRange.GetOffset(PlanViewPlane.BottomClipPlane), "Bottom clip plane") + .Add(viewRange.GetOffset(PlanViewPlane.UnderlayBottom), "Underlay bottom") + .Consume(); + } + + IVariant ResolveGetLevelId() + { + return Variants.Values(4) + .Add(viewRange.GetLevelId(PlanViewPlane.TopClipPlane), "Top clip plane") + .Add(viewRange.GetLevelId(PlanViewPlane.CutPlane), "Cut plane") + .Add(viewRange.GetLevelId(PlanViewPlane.BottomClipPlane), "Bottom clip plane") + .Add(viewRange.GetLevelId(PlanViewPlane.UnderlayBottom), "Underlay bottom") + .Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/PrintManagerDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/PrintManagerDescriptor.cs new file mode 100644 index 000000000..40f9c7234 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/PrintManagerDescriptor.cs @@ -0,0 +1,42 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class PrintManagerDescriptor : Descriptor, IDescriptorResolver +{ + public PrintManagerDescriptor(PrintManager printManager) + { + Name = printManager.PrinterName; + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(PrintManager.SubmitPrint) when parameters.Length == 0 => Variants.Disabled, + _ => null + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ReferenceDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ReferenceDescriptor.cs new file mode 100644 index 000000000..8ce5d7a9a --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ReferenceDescriptor.cs @@ -0,0 +1,70 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.UI.Framework.Extensions; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ReferenceDescriptor : Descriptor, IDescriptorResolver, IContextMenuConnector +{ + private readonly Reference _reference; + + public ReferenceDescriptor(Reference reference) + { + _reference = reference; + Name = reference.ElementReferenceType.ToString(); + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Reference.ConvertToStableRepresentation) => ResolveConvertToStableRepresentation, + _ => null + }; + + IVariant ResolveConvertToStableRepresentation(Document context) + { + return Variants.Value(_reference.ConvertToStableRepresentation(context)); + } + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { +#if REVIT2023_OR_GREATER + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_reference, SelectReference) + .SetShortcut(Key.F6); + + void SelectReference(Reference reference) + { + if (Context.ActiveUiDocument is null) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetReferences([reference])); + } +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/RevisionNumberingSequenceDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/RevisionNumberingSequenceDescriptor.cs new file mode 100644 index 000000000..31344b1c2 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/RevisionNumberingSequenceDescriptor.cs @@ -0,0 +1,55 @@ +#if REVIT2022_OR_GREATER +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class RevisionNumberingSequenceDescriptor(RevisionNumberingSequence sequence) : ElementDescriptor(sequence) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(RevisionNumberingSequence.GetAllRevisionNumberingSequences) => ResolveRevisionNumberingSequences, + _ => null + }; + + IVariant ResolveRevisionNumberingSequences() + { + var ids = RevisionNumberingSequence.GetAllRevisionNumberingSequences(sequence.Document); + var variants = Variants.Values(ids.Count); + foreach (var id in ids) + { + variants.Add(id); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} +#endif \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/RevitLinkTypeDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/RevitLinkTypeDescriptor.cs new file mode 100644 index 000000000..43bf5a554 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/RevitLinkTypeDescriptor.cs @@ -0,0 +1,48 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class RevitLinkTypeDescriptor(RevitLinkType element) : ElementDescriptor(element) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(RevitLinkType.Load) => Variants.Disabled, + nameof(RevitLinkType.Reload) => Variants.Disabled, + nameof(RevitLinkType.IsLoaded) => ResolveIsLoaded, + _ => null + }; + + IVariant ResolveIsLoaded() + { + return Variants.Value(RevitLinkType.IsLoaded(element.Document, element.Id)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Diagnostic/ClockDiagnoser.cs b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonItemDescriptor.cs similarity index 69% rename from source/RevitLookup/Core/Diagnostic/ClockDiagnoser.cs rename to source/RevitLookup/Core/Decomposition/Descriptors/RibbonItemDescriptor.cs index f16d47eef..8e3c2edbe 100644 --- a/source/RevitLookup/Core/Diagnostic/ClockDiagnoser.cs +++ b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonItemDescriptor.cs @@ -18,29 +18,21 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -using System.Diagnostics; +using Autodesk.Revit.UI; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; -namespace RevitLookup.Core.Diagnostic; +namespace RevitLookup.Core.Decomposition.Descriptors; -public sealed class ClockDiagnoser +public sealed class RibbonItemDescriptor : Descriptor, IDescriptorCollector { - private readonly Stopwatch _clock = new(); - - public void Start() + public RibbonItemDescriptor(RibbonItem item) { - _clock.Start(); + Name = item.ItemText; } - - public void Stop() - { - _clock.Stop(); - } - - public TimeSpan GetElapsed() + + public RibbonItemDescriptor(Autodesk.Windows.RibbonItem panel) { - var elapsed = _clock.Elapsed; - _clock.Reset(); - - return elapsed; + Name = panel.TextOverride; } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/RibbonPanelDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonPanelDescriptor.cs new file mode 100644 index 000000000..4b78e491b --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonPanelDescriptor.cs @@ -0,0 +1,38 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.UI; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class RibbonPanelDescriptor : Descriptor, IDescriptorCollector +{ + public RibbonPanelDescriptor(RibbonPanel panel) + { + Name = panel.Name; + } + + public RibbonPanelDescriptor(Autodesk.Windows.RibbonPanel panel) + { + if (panel.Source is not null) Name = panel.Source.AutomationName; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/RibbonTabDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonTabDescriptor.cs new file mode 100644 index 000000000..c65d75d95 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/RibbonTabDescriptor.cs @@ -0,0 +1,33 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Windows; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class RibbonTabDescriptor : Descriptor, IDescriptorCollector +{ + public RibbonTabDescriptor(RibbonTab ribbonTab) + { + Name = ribbonTab.Title; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/SchedulableFieldDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/SchedulableFieldDescriptor.cs new file mode 100644 index 000000000..8aa0f9363 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/SchedulableFieldDescriptor.cs @@ -0,0 +1,50 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class SchedulableFieldDescriptor : Descriptor, IDescriptorResolver +{ + private readonly SchedulableField _field; + + public SchedulableFieldDescriptor(SchedulableField field) + { + _field = field; + Name = field.GetName(Context.ActiveDocument); + } + + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(SchedulableField.GetName) => ResolveGetName, + _ => null + }; + + IVariant ResolveGetName(Document context) + { + return Variants.Value(_field.GetName(context)); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ScheduleDefinitionDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ScheduleDefinitionDescriptor.cs new file mode 100644 index 000000000..0f3857c4a --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ScheduleDefinitionDescriptor.cs @@ -0,0 +1,220 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ScheduleDefinitionDescriptor(ScheduleDefinition scheduleDefinition) : Descriptor, IDescriptorResolver, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ScheduleDefinition.CanFilterByGlobalParameters) => ResolveFilterByGlobalParameters, + nameof(ScheduleDefinition.CanFilterByParameterExistence) => ResolveFilterByParameterExistence, + nameof(ScheduleDefinition.CanFilterBySubstring) => ResolveFilterBySubstring, + nameof(ScheduleDefinition.CanFilterByValue) => ResolveFilterByValue, + nameof(ScheduleDefinition.CanFilterByValuePresence) => ResolveFilterByValuePresence, + nameof(ScheduleDefinition.CanSortByField) => ResolveSortByField, + nameof(ScheduleDefinition.GetField) => ResolveGetField, + nameof(ScheduleDefinition.GetFieldId) => ResolveGetFieldId, + nameof(ScheduleDefinition.GetFieldIndex) => ResolveGetFieldIndex, + nameof(ScheduleDefinition.GetFilter) => ResolveGetFilter, + nameof(ScheduleDefinition.GetSortGroupField) => ResolveGetSortGroupField, + _ => null + }; + + IVariant ResolveFilterByGlobalParameters() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanFilterByGlobalParameters(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterByParameterExistence() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanFilterByParameterExistence(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterBySubstring() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanFilterBySubstring(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterByValue() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanFilterByValue(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterByValuePresence() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanFilterByValuePresence(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveSortByField() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.CanSortByField(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetField() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.GetField(field); + variants.Add(result, $"{result.GetName()}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetFieldId() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.GetFieldId(field.IntegerValue); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetFieldIndex() + { + var fields = scheduleDefinition.GetFieldOrder(); + var variants = Variants.Values(fields.Count); + foreach (var field in fields) + { + var result = scheduleDefinition.GetFieldIndex(field); + var name = scheduleDefinition.GetField(field).GetName(); + variants.Add(result, $"{name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveGetFilter() + { + var count = scheduleDefinition.GetFilterCount(); + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + variants.Add(scheduleDefinition.GetFilter(i)); + } + + return variants.Consume(); + } + + IVariant ResolveGetSortGroupField() + { + var count = scheduleDefinition.GetSortGroupFieldCount(); + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + variants.Add(scheduleDefinition.GetSortGroupField(i)); + } + + return variants.Consume(); + } + } + + Func? IDescriptorResolver.Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ScheduleDefinition.IsValidCategoryForEmbeddedSchedule) => ResolveValidCategoryForEmbeddedSchedule, + _ => null + }; + + IVariant ResolveValidCategoryForEmbeddedSchedule(Document context) + { + var categories = context.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + if (scheduleDefinition.IsValidCategoryForEmbeddedSchedule(category.Id)) + { + variants.Add(true, category.Name); + } + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/SchemaDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/SchemaDescriptor.cs new file mode 100644 index 000000000..4f0d09bb9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/SchemaDescriptor.cs @@ -0,0 +1,44 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.ExtensibleStorage; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class SchemaDescriptor : Descriptor, IDescriptorExtension +{ + private readonly Schema _schema; + + public SchemaDescriptor(Schema schema) + { + _schema = schema; + Name = schema.SchemaName; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register("GetElements", context => Variants.Value(context + .GetElements() + .WherePasses(new ExtensibleStorageFilter(_schema.GUID)) + .ToElements())); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/SolidDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/SolidDescriptor.cs new file mode 100644 index 000000000..b57bef290 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/SolidDescriptor.cs @@ -0,0 +1,147 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class SolidDescriptor : Descriptor, IDescriptorExtension, IContextMenuConnector +{ + private readonly Solid _solid; + + public SolidDescriptor(Solid solid) + { + _solid = solid; + Name = $"{solid.Volume.ToString(CultureInfo.InvariantCulture)} ft³"; + } + + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(SolidUtils.SplitVolumes), () => Variants.Value(SolidUtils.SplitVolumes(_solid))); + manager.Register(nameof(SolidUtils.IsValidForTessellation), () => Variants.Value(SolidUtils.IsValidForTessellation(_solid))); + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { +#if REVIT2023_OR_GREATER + contextMenu.AddMenuItem("SelectMenuItem") + .SetCommand(_solid, SelectSolid) + .SetShortcut(Key.F6); + + contextMenu.AddMenuItem("ShowMenuItem") + .SetCommand(_solid, ShowSolid) + .SetShortcut(Key.F7); +#endif + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability(_solid.IsValidForTessellation()) + .SetCommand(_solid, VisualizeSolid) + .SetShortcut(Key.F8); + + async Task VisualizeSolid(Solid solid) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(solid); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize solid error"); + notificationService.ShowError("Visualization error", exception); + } + } + +#if REVIT2023_OR_GREATER + void SelectSolid(Solid solid) + { + try + { + if (Context.ActiveUiDocument is null) return; + + var references = solid.Faces.Cast() + .Select(face => face.Reference) + .Where(reference => reference is not null) + .ToList(); + + if (references.Count == 0) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.ActiveUiDocument.Selection.SetReferences(references)); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Select solid error"); + notificationService.ShowError("Selection error", exception); + } + } + + void ShowSolid(Solid solid) + { + try + { + if (Context.ActiveUiDocument is null) return; + + var references = solid.Faces.Cast() + .Select(face => face.Reference) + .Where(reference => reference is not null) + .ToList(); + + if (references.Count == 0) return; + + RevitShell.ActionEventHandler.Raise(application => + { + var uiDocument = application.ActiveUIDocument; + if (uiDocument is null) return; + + var element = references[0].ElementId.ToElement(uiDocument.Document); + if (element is not null) uiDocument.ShowElements(element); + + uiDocument.Selection.SetReferences(references); + }); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Show solid error"); + notificationService.ShowError("Showing error", exception); + } + } +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/SpatialElementDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/SpatialElementDescriptor.cs new file mode 100644 index 000000000..7debb71a1 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/SpatialElementDescriptor.cs @@ -0,0 +1,87 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class SpatialElementDescriptor(SpatialElement spatialElement) : ElementDescriptor(spatialElement) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(SpatialElement.GetBoundarySegments) => ResolveGetBoundarySegments, + _ => null + }; + + IVariant ResolveGetBoundarySegments() + { + return Variants.Values>>(8) + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center, + StoreFreeBoundaryFaces = true + }), "Center, store free boundary faces") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.CoreBoundary, + StoreFreeBoundaryFaces = true + }), "Core boundary, store free boundary faces") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish, + StoreFreeBoundaryFaces = true + }), "Finish, store free boundary faces") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.CoreCenter, + StoreFreeBoundaryFaces = true + }), "Core center, store free boundary faces") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Center, + StoreFreeBoundaryFaces = true + }), "Center") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.CoreBoundary, + StoreFreeBoundaryFaces = true + }), "Core boundary") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.Finish, + StoreFreeBoundaryFaces = true + }), "Finish") + .Add(spatialElement.GetBoundarySegments(new SpatialElementBoundaryOptions + { + SpatialElementBoundaryLocation = SpatialElementBoundaryLocation.CoreCenter, + StoreFreeBoundaryFaces = true + }), "Core center") + .Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/StructuralSettingsDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/StructuralSettingsDescriptor.cs new file mode 100644 index 000000000..d35878942 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/StructuralSettingsDescriptor.cs @@ -0,0 +1,47 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Structure; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class StructuralSettingsDescriptor(StructuralSettings structuralSettings) : ElementDescriptor(structuralSettings) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(StructuralSettings.GetStructuralSettings) => ResolveGet, + _ => null + }; + + IVariant ResolveGet() + { + return Variants.Value(StructuralSettings.GetStructuralSettings(structuralSettings.Document)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/SunAndShadowSettingsDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/SunAndShadowSettingsDescriptor.cs new file mode 100644 index 000000000..dfcf9d209 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/SunAndShadowSettingsDescriptor.cs @@ -0,0 +1,85 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class SunAndShadowSettingsDescriptor(SunAndShadowSettings settings) : ElementDescriptor(settings) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(SunAndShadowSettings.GetActiveSunAndShadowSettings) => ResolveGet, + nameof(SunAndShadowSettings.GetSunrise) => ResolveGetSunrise, + nameof(SunAndShadowSettings.GetSunset) => ResolveGetSunset, + nameof(SunAndShadowSettings.IsTimeIntervalValid) => ResolveTimeInterval, + nameof(SunAndShadowSettings.IsAfterStartDateAndTime) => ResolveAfterStart, + nameof(SunAndShadowSettings.IsBeforeEndDateAndTime) => ResolveBeforeStart, + _ => null + }; + + IVariant ResolveGet() + { + return Variants.Value(SunAndShadowSettings.GetActiveSunAndShadowSettings(settings.Document)); + } + + IVariant ResolveGetSunrise() + { + return Variants.Value(settings.GetSunrise(DateTime.Today)); + } + + IVariant ResolveGetSunset() + { + return Variants.Value(settings.GetSunset(DateTime.Today)); + } + + IVariant ResolveAfterStart() + { + return Variants.Value(settings.IsAfterStartDateAndTime(DateTime.Today)); + } + + IVariant ResolveBeforeStart() + { + return Variants.Value(settings.IsBeforeEndDateAndTime(DateTime.Today)); + } + + IVariant ResolveTimeInterval() + { + var conditions = Enum.GetValues(typeof(SunStudyTimeInterval)); + var variants = Variants.Values(conditions.Length); + + foreach (SunStudyTimeInterval condition in conditions) + { + var result = settings.IsTimeIntervalValid(condition); + variants.Add(result, $"{condition}: {result}"); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/TableDataDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/TableDataDescriptor.cs new file mode 100644 index 000000000..d218a127f --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/TableDataDescriptor.cs @@ -0,0 +1,89 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class TableDataDescriptor(TableData tableData) : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(TableData.GetSectionData) when parameters.Length == 1 && + parameters[0].ParameterType == typeof(SectionType) => ResolveSectionDataBySectionType, + nameof(TableData.GetSectionData) when parameters.Length == 1 && + parameters[0].ParameterType == typeof(int) => ResolveSectionDataByIndex, + nameof(TableData.IsValidZoomLevel) => ResolveZoomLevel, + _ => null + }; + + IVariant ResolveSectionDataBySectionType() + { + var sectionTypes = Enum.GetValues(typeof(SectionType)); + var variants = Variants.Values(sectionTypes.Length); + foreach (SectionType sectionType in sectionTypes) + { + variants.Add(tableData.GetSectionData(sectionType), sectionType.ToString()); + } + + return variants.Consume(); + } + + IVariant ResolveSectionDataByIndex() + { + var variants = Variants.Values(tableData.NumberOfSections); + for (var i = 0; i < tableData.NumberOfSections; i++) + { + variants.Add(tableData.GetSectionData(i), i.ToString()); + } + + return variants.Consume(); + } + + IVariant ResolveZoomLevel() + { + var variants = Variants.Values(512); + + var zoom = 0; + var emptyIterations = 0; + while (emptyIterations < 50) + { + var isValid = tableData.IsValidZoomLevel(zoom); + if (isValid) + { + variants.Add(true, $"{zoom}: valid"); + emptyIterations = 0; + } + else + { + emptyIterations++; + } + + zoom++; + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/TableSectionDataDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/TableSectionDataDescriptor.cs new file mode 100644 index 000000000..428eeebf4 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/TableSectionDataDescriptor.cs @@ -0,0 +1,540 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Globalization; +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class TableSectionDataDescriptor(TableSectionData tableSectionData) : Descriptor, IDescriptorResolver, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(TableSectionData.AllowOverrideCellStyle) => ResolveOverrideCellStyle, + nameof(TableSectionData.CanInsertColumn) => ResolveCanInsertColumn, + nameof(TableSectionData.CanInsertRow) => ResolveCanInsertRow, + nameof(TableSectionData.CanRemoveColumn) => ResolveCanRemoveColumn, + nameof(TableSectionData.CanRemoveRow) => ResolveCanRemoveRow, + nameof(TableSectionData.GetCellCalculatedValue) when parameters.Length == 1 => ResolveCellCalculatedValueForColumns, + nameof(TableSectionData.GetCellCalculatedValue) when parameters.Length == 2 => ResolveCellCalculatedValueForTable, + nameof(TableSectionData.GetCellCombinedParameters) when parameters.Length == 1 => ResolveCellCombinedParametersForColumns, + nameof(TableSectionData.GetCellCombinedParameters) when parameters.Length == 2 => ResolveCellCombinedParametersForTable, + nameof(TableSectionData.GetCellSpec) => ResolveCellSpec, + nameof(TableSectionData.GetCellText) => ResolveCellText, + nameof(TableSectionData.GetCellType) when parameters.Length == 1 => ResolveCellTypeForColumns, + nameof(TableSectionData.GetCellType) when parameters.Length == 2 => ResolveCellTypeForTable, + nameof(TableSectionData.GetColumnWidth) => ResolveColumnWidth, + nameof(TableSectionData.GetColumnWidthInPixels) => ResolveColumnWidthInPixels, + nameof(TableSectionData.GetMergedCell) => ResolveMergedCell, + nameof(TableSectionData.GetRowHeight) => ResolveRowHeight, + nameof(TableSectionData.GetRowHeightInPixels) => ResolveRowHeightInPixels, + nameof(TableSectionData.GetTableCellStyle) => ResolveTableCellStyle, + nameof(TableSectionData.IsCellFormattable) => ResolveIsCellFormattable, + nameof(TableSectionData.IsCellOverridden) when parameters.Length == 1 => ResolveIsCellOverriddenForColumns, + nameof(TableSectionData.IsCellOverridden) when parameters.Length == 2 => ResolveIsCellOverriddenForTable, + nameof(TableSectionData.IsValidColumnNumber) => ResolveIsValidColumnNumber, + nameof(TableSectionData.IsValidRowNumber) => ResolveIsValidRowNumber, + nameof(TableSectionData.RefreshData) => Variants.Disabled, + _ => null + }; + + IVariant ResolveOverrideCellStyle() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < rowsNumber; i++) + { + for (var j = 0; j < columnsNumber; j++) + { + var result = tableSectionData.AllowOverrideCellStyle(i, j); + variants.Add(result, $"Row {i}, Column {j}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCanInsertColumn() + { + var count = tableSectionData.NumberOfColumns; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.CanInsertColumn(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanInsertRow() + { + var count = tableSectionData.NumberOfRows; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.CanInsertRow(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanRemoveColumn() + { + var count = tableSectionData.NumberOfColumns; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.CanRemoveColumn(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanRemoveRow() + { + var count = tableSectionData.NumberOfRows; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.CanRemoveRow(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellCalculatedValueForColumns() + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var j = 0; j < columnsNumber; j++) + { + var result = tableSectionData.GetCellCalculatedValue(j); + variants.Add(result, $"Column {j}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellCalculatedValueForTable() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < rowsNumber; i++) + { + for (var j = 0; j < columnsNumber; j++) + { + var result = tableSectionData.GetCellCalculatedValue(i, j); + variants.Add(result, $"Row {i}, Column {j}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellCombinedParametersForColumns() + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values>(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.GetCellCombinedParameters(i); + variants.Add(result, $"Column {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellCombinedParametersForTable() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values>(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellCombinedParameters(j, i); + variants.Add(result, $"Row {j}, Column {i}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellSpec() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellSpec(j, i); + if (result.Empty()) continue; + + variants.Add(result, $"Row {j}, Column {i}: {result.ToSpecLabel()}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellText() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellText(j, i); + variants.Add(result, $"Row {j}, Column {i}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellTypeForColumns() + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.GetCellType(i); + variants.Add(result, $"Column {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellTypeForTable() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellType(j, i); + variants.Add(result, $"Row {j}, Column {i}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveColumnWidth() + { + var count = tableSectionData.NumberOfColumns; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.GetColumnWidth(i); + variants.Add(result, $"{i}: {result.ToString(CultureInfo.InvariantCulture)}"); + } + + return variants.Consume(); + } + + + IVariant ResolveColumnWidthInPixels() + { + var count = tableSectionData.NumberOfColumns; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.GetColumnWidthInPixels(i); + variants.Add(result, $"{i}: {result.ToString(CultureInfo.InvariantCulture)}"); + } + + return variants.Consume(); + } + + IVariant ResolveMergedCell() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetMergedCell(j, i); + variants.Add(result, $"Row {j}, Column {i}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveRowHeight() + { + var count = tableSectionData.NumberOfRows; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.GetRowHeight(i); + variants.Add(result, $"{i}: {result.ToString(CultureInfo.InvariantCulture)}"); + } + + return variants.Consume(); + } + + IVariant ResolveRowHeightInPixels() + { + var count = tableSectionData.NumberOfRows; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.GetRowHeightInPixels(i); + variants.Add(result, $"{i}: {result.ToString(CultureInfo.InvariantCulture)}"); + } + + return variants.Consume(); + } + + IVariant ResolveTableCellStyle() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetTableCellStyle(j, i); + variants.Add(result, $"Row {j}, Column {i}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveIsCellFormattable() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.IsCellFormattable(j, i); + variants.Add(result, $"Row {j}, Column {i}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveIsCellOverriddenForColumns() + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.IsCellOverridden(i); + variants.Add(result, $"Column {i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsCellOverriddenForTable() + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.IsCellOverridden(j, i); + variants.Add(result, $"Row {j}, Column {i}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveIsValidColumnNumber() + { + var count = tableSectionData.NumberOfColumns; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.IsValidColumnNumber(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidRowNumber() + { + var count = tableSectionData.NumberOfRows; + var variants = Variants.Values(count); + for (var i = 0; i < count; i++) + { + var result = tableSectionData.IsValidRowNumber(i); + variants.Add(result, $"{i}: {result}"); + } + + return variants.Consume(); + } + } + + Func? IDescriptorResolver.Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(TableSectionData.GetCellCategoryId) when parameters.Length == 1 => ResolveCellCategoryIdForColumns, + nameof(TableSectionData.GetCellCategoryId) when parameters.Length == 2 => ResolveCellCategoryIdForTable, + nameof(TableSectionData.GetCellFormatOptions) when parameters.Length == 2 => ResolveCellFormatOptionsForColumns, + nameof(TableSectionData.GetCellFormatOptions) when parameters.Length == 3 => ResolveCellFormatOptionsForTable, + nameof(TableSectionData.GetCellParamId) when parameters.Length == 1 => ResolveCellParamIdForColumns, + nameof(TableSectionData.GetCellParamId) when parameters.Length == 2 => ResolveCellParamIdForTable, + _ => null + }; + + IVariant ResolveCellCategoryIdForColumns(Document context) + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.GetCellCategoryId(i); + if (result == ElementId.InvalidElementId) continue; + + var category = Category.GetCategory(context, result); + if (category is null) continue; + + variants.Add(result, $"Column {i}: {category.Name}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellCategoryIdForTable(Document context) + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellCategoryId(j, i); + if (result == ElementId.InvalidElementId) continue; + + var category = Category.GetCategory(context, result); + if (category is null) continue; + + variants.Add(result, $"Row {j}, Column {i}: {category.Name}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellFormatOptionsForColumns(Document context) + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.GetCellFormatOptions(i, context); + variants.Add(result, $"Column {i}"); + } + + return variants.Consume(); + } + + IVariant ResolveCellFormatOptionsForTable(Document context) + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellFormatOptions(j, i, context); + variants.Add(result, $"Row {j}, Column {i}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellParamIdForColumns(Document context) + { + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + var result = tableSectionData.GetCellParamId(i); + if (result != ElementId.InvalidElementId) + { + var parameter = result.ToElement(context); + variants.Add(result, $"Column {i}: {parameter!.Name}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellParamIdForTable(Document context) + { + var rowsNumber = tableSectionData.NumberOfRows; + var columnsNumber = tableSectionData.NumberOfColumns; + var variants = Variants.Values(rowsNumber * columnsNumber); + for (var i = 0; i < columnsNumber; i++) + { + for (var j = 0; j < rowsNumber; j++) + { + var result = tableSectionData.GetCellParamId(j, i); + if (result == ElementId.InvalidElementId) continue; + + var parameter = result.ToElement(context); + if (parameter is null) continue; + + variants.Add(result, $"Row {j}, Column {i}: {parameter.Name}"); + } + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/TableViewDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/TableViewDescriptor.cs new file mode 100644 index 000000000..b5f2e0c7c --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/TableViewDescriptor.cs @@ -0,0 +1,148 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Electrical; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class TableViewDescriptor(TableView tableView) : ElementDescriptor(tableView) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + // nameof(TableView.GetAvailableParameterCategories) => ResolveAvailableParameterCategories, disabled, long computation time + nameof(TableView.GetAvailableParameters) => ResolveAvailableParameters, + nameof(TableView.GetCalculatedValueName) => ResolveCalculatedValueName, + nameof(TableView.GetCalculatedValueText) => ResolveCalculatedValueText, + nameof(TableView.IsValidSectionType) => ResolveIsValidSectionType, + nameof(TableView.GetCellText) => ResolveCellText, + _ => null + }; + + IVariant ResolveAvailableParameters() + { + var categories = tableView.Document.Settings.Categories; + var variants = Variants.Values>(categories.Size); + foreach (Category category in categories) + { + var result = TableView.GetAvailableParameters(tableView.Document, category.Id); + variants.Add(result, $"{category.Name}"); + } + + return variants.Consume(); + } + + IVariant ResolveCalculatedValueName() + { + var tableData = tableView switch + { + ViewSchedule viewSchedule => viewSchedule.GetTableData(), + PanelScheduleView panelScheduleView => panelScheduleView.GetTableData(), + _ => throw new NotSupportedException($"{tableView.GetType().FullName} is not supported in the current API version") + }; + + var sectionTypes = Enum.GetValues(typeof(SectionType)); + var variants = Variants.Values(sectionTypes.Length); + foreach (SectionType sectionType in sectionTypes) + { + var tableSectionData = tableData!.GetSectionData(sectionType); + if (tableSectionData is null) continue; + + for (var i = tableSectionData.FirstRowNumber; i < tableSectionData.LastRowNumber; i++) + for (var j = tableSectionData.FirstColumnNumber; j < tableSectionData.LastColumnNumber; j++) + { + var result = tableView.GetCalculatedValueName(sectionType, i, j); + variants.Add(result, $"{sectionType}, row {i}, column {j}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCalculatedValueText() + { + var tableData = tableView switch + { + ViewSchedule viewSchedule => viewSchedule.GetTableData(), + PanelScheduleView panelScheduleView => panelScheduleView.GetTableData(), + _ => throw new NotSupportedException($"{tableView.GetType().FullName} is not supported in the current API version") + }; + + var sectionTypes = Enum.GetValues(typeof(SectionType)); + var variants = Variants.Values(sectionTypes.Length); + foreach (SectionType sectionType in sectionTypes) + { + var tableSectionData = tableData!.GetSectionData(sectionType); + if (tableSectionData is null) continue; + + for (var i = tableSectionData.FirstRowNumber; i < tableSectionData.LastRowNumber; i++) + for (var j = tableSectionData.FirstColumnNumber; j < tableSectionData.LastColumnNumber; j++) + { + var result = tableView.GetCalculatedValueText(sectionType, i, j); + variants.Add(result, $"{sectionType}, row {i}, column {j}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveCellText() + { + var tableData = tableView switch + { + ViewSchedule viewSchedule => viewSchedule.GetTableData(), + PanelScheduleView panelScheduleView => panelScheduleView.GetTableData(), + _ => throw new NotSupportedException($"{tableView.GetType().FullName} is not supported in the current API version") + }; + + var sectionTypes = Enum.GetValues(typeof(SectionType)); + var variants = Variants.Values(sectionTypes.Length); + foreach (SectionType sectionType in sectionTypes) + { + var tableSectionData = tableData!.GetSectionData(sectionType); + if (tableSectionData is null) continue; + for (var i = tableSectionData.FirstRowNumber; i < tableSectionData.LastRowNumber; i++) + for (var j = tableSectionData.FirstColumnNumber; j < tableSectionData.LastColumnNumber; j++) + { + var result = tableView.GetCellText(sectionType, i, j); + variants.Add(result, $"{sectionType}, row {i}, column {j}: {result}"); + } + } + + return variants.Consume(); + } + + IVariant ResolveIsValidSectionType() + { + var sectionTypes = Enum.GetValues(typeof(SectionType)); + var variants = Variants.Values(sectionTypes.Length); + foreach (SectionType sectionType in sectionTypes) + { + var result = tableView.IsValidSectionType(sectionType); + variants.Add(result, $"{sectionType}: {result}"); + } + + return variants.Consume(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/UiApplicationDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/UiApplicationDescriptor.cs new file mode 100644 index 000000000..fb21d68a8 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/UiApplicationDescriptor.cs @@ -0,0 +1,37 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.UI; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class UiApplicationDescriptor : Descriptor, IDescriptorExtension +{ + public void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(UIThemeManager.CurrentTheme), () => Variants.Value(UIThemeManager.CurrentTheme)); +#if REVIT2024_OR_GREATER + manager.Register(nameof(UIThemeManager.CurrentCanvasTheme), () => Variants.Value(UIThemeManager.CurrentCanvasTheme)); + manager.Register(nameof(UIThemeManager.FollowSystemColorTheme), () => Variants.Value(UIThemeManager.FollowSystemColorTheme)); +#endif + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/UiElementDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/UiElementDescriptor.cs new file mode 100644 index 000000000..00861e042 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/UiElementDescriptor.cs @@ -0,0 +1,47 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Windows; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class UiElementDescriptor : Descriptor, IDescriptorResolver +{ + public Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(UIElement.GetLocalValueEnumerator) => ResolveGetLocalValueEnumerator, + nameof(UIElement.CaptureMouse) => Variants.Disabled, + nameof(UIElement.CaptureStylus) => Variants.Disabled, + nameof(UIElement.Focus) => Variants.Disabled, + "Enter" => Variants.Disabled, + _ => null + }; + + IVariant ResolveGetLocalValueEnumerator() + { + return Variants.Empty(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/UiObjectDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/UiObjectDescriptor.cs new file mode 100644 index 000000000..e9f0783d9 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/UiObjectDescriptor.cs @@ -0,0 +1,26 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class UiObjectDescriptor : Descriptor, IDescriptorCollector; \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/UpdaterInfoDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/UpdaterInfoDescriptor.cs new file mode 100644 index 000000000..8883d2f06 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/UpdaterInfoDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class UpdaterInfoDescriptor : Descriptor, IDescriptorCollector +{ + public UpdaterInfoDescriptor(UpdaterInfo info) + { + Name = info.UpdaterName; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ViewDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ViewDescriptor.cs new file mode 100644 index 000000000..47cfafb4d --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ViewDescriptor.cs @@ -0,0 +1,277 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Analysis; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ViewDescriptor(View view) : ElementDescriptor(view) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(View.CanCategoryBeHidden) => ResolveCanCategoryBeHidden, + nameof(View.CanCategoryBeHiddenTemporary) => ResolveCanCategoryBeHiddenTemporary, + nameof(View.CanViewBeDuplicated) => ResolveCanViewBeDuplicated, + nameof(View.GetCategoryHidden) => ResolveCategoryHidden, + nameof(View.GetCategoryOverrides) => ResolveCategoryOverrides, + nameof(View.GetIsFilterEnabled) => ResolveFilterEnabled, + nameof(View.GetFilterOverrides) => ResolveFilterOverrides, + nameof(View.GetFilterVisibility) => ResolveFilterVisibility, + nameof(View.GetWorksetVisibility) => ResolveWorksetVisibility, + nameof(View.IsCategoryOverridable) => ResolveIsCategoryOverridable, + nameof(View.IsFilterApplied) => ResolveIsFilterApplied, + nameof(View.IsInTemporaryViewMode) => ResolveIsInTemporaryViewMode, + nameof(View.IsValidViewTemplate) => ResolveIsValidViewTemplate, + nameof(View.IsWorksetVisible) => ResolveIsWorksetVisible, + nameof(View.SupportsWorksharingDisplayMode) => ResolveSupportsWorksharingDisplayMode, +#if REVIT2022_OR_GREATER + nameof(View.GetColorFillSchemeId) => ResolveColorFillSchemeId, +#endif + _ => null + }; + + IVariant ResolveCanCategoryBeHidden() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.CanCategoryBeHidden(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanCategoryBeHiddenTemporary() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.CanCategoryBeHiddenTemporary(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCanViewBeDuplicated() + { + var values = Enum.GetValues(typeof(ViewDuplicateOption)); + var variants = Variants.Values(values.Length); + + foreach (ViewDuplicateOption option in values) + { + var result = view.CanViewBeDuplicated(option); + variants.Add(result, $"{option.ToString()}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCategoryHidden() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.GetCategoryHidden(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveCategoryOverrides() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.GetCategoryOverrides(category.Id); + variants.Add(result, category.Name); + } + + return variants.Consume(); + } + + IVariant ResolveIsCategoryOverridable() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.IsCategoryOverridable(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterOverrides() + { + var filters = view.GetFilters(); + var variants = Variants.Values(filters.Count); + foreach (var filterId in filters) + { + var filter = filterId.ToElement(view.Document)!; + var result = view.GetFilterOverrides(filterId); + variants.Add(result, filter.Name); + } + + return variants.Consume(); + } + + IVariant ResolveFilterVisibility() + { + var filters = view.GetFilters(); + var variants = Variants.Values(filters.Count); + foreach (var filterId in filters) + { + var filter = filterId.ToElement(view.Document)!; + var result = view.GetFilterVisibility(filterId); + variants.Add(result, $"{filter.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveFilterEnabled() + { + var filters = view.GetFilters(); + var variants = Variants.Values(filters.Count); + foreach (var filterId in filters) + { + var filter = filterId.ToElement(view.Document)!; + var result = view.GetIsFilterEnabled(filterId); + variants.Add(result, $"{filter.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsFilterApplied() + { + var filters = view.GetFilters(); + var variants = Variants.Values(filters.Count); + foreach (var filterId in filters) + { + var filter = filterId.ToElement(view.Document)!; + var result = view.IsFilterApplied(filterId); + variants.Add(result, $"{filter.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsInTemporaryViewMode() + { + var values = Enum.GetValues(typeof(TemporaryViewMode)); + var variants = Variants.Values(values.Length); + + foreach (TemporaryViewMode mode in values) + { + var result = view.IsInTemporaryViewMode(mode); + variants.Add(result, $"{mode.ToString()}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidViewTemplate() + { + var templates = view.Document.EnumerateInstances().Where(x => x.IsTemplate).ToArray(); + var variants = Variants.Values(templates.Length); + foreach (var template in templates) + { + var result = view.IsValidViewTemplate(template.Id); + variants.Add(result, $"{template.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsWorksetVisible() + { + var workSets = new FilteredWorksetCollector(view.Document).OfKind(WorksetKind.UserWorkset).ToWorksets(); + var variants = Variants.Values(workSets.Count); + foreach (var workSet in workSets) + { + var result = view.IsWorksetVisible(workSet.Id); + variants.Add(result, $"{workSet.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveWorksetVisibility() + { + var workSets = new FilteredWorksetCollector(view.Document).OfKind(WorksetKind.UserWorkset).ToWorksets(); + var variants = Variants.Values(workSets.Count); + foreach (var workSet in workSets) + { + var result = view.GetWorksetVisibility(workSet.Id); + variants.Add(result, $"{workSet.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveSupportsWorksharingDisplayMode() + { + var values = Enum.GetValues(typeof(WorksharingDisplayMode)); + var variants = Variants.Values(values.Length); + + foreach (WorksharingDisplayMode mode in values) + { + var result = view.SupportsWorksharingDisplayMode(mode); + variants.Add(result, $"{mode.ToString()}: {result}"); + } + + return variants.Consume(); + } +#if REVIT2022_OR_GREATER + + IVariant ResolveColorFillSchemeId() + { + var categories = view.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = view.GetColorFillSchemeId(category.Id); + variants.Add(result, category.Name); + } + + return variants.Consume(); + } +#endif + } + + public override void RegisterExtensions(IExtensionManager manager) + { + manager.Register(nameof(SpatialFieldManager.GetSpatialFieldManager), () => Variants.Value(SpatialFieldManager.GetSpatialFieldManager(view))); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/ViewScheduleDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/ViewScheduleDescriptor.cs new file mode 100644 index 000000000..7f13cf04c --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/ViewScheduleDescriptor.cs @@ -0,0 +1,245 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class ViewScheduleDescriptor(ViewSchedule viewSchedule) : ElementDescriptor(viewSchedule) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(ViewSchedule.GetStripedRowsColor) => ResolveStripedRowsColor, + nameof(ViewSchedule.IsValidTextTypeId) => ResolveValidTextTypeId, + nameof(ViewSchedule.GetDefaultNameForKeySchedule) => ResolveDefaultNameForKeySchedule, + nameof(ViewSchedule.GetDefaultNameForMaterialTakeoff) => ResolveDefaultNameForMaterialTakeoff, + nameof(ViewSchedule.GetDefaultNameForSchedule) => ResolveDefaultNameForSchedule, + nameof(ViewSchedule.GetDefaultParameterNameForKeySchedule) => ResolveDefaultParameterNameForKeySchedule, + nameof(ViewSchedule.IsValidCategoryForKeySchedule) => ResolveIsValidCategoryForKeySchedule, + nameof(ViewSchedule.IsValidCategoryForMaterialTakeoff) => ResolveIsValidCategoryForMaterialTakeoff, + nameof(ViewSchedule.IsValidCategoryForSchedule) => ResolveIsValidCategoryForSchedule, + nameof(ViewSchedule.GetDefaultNameForKeynoteLegend) => ResolveGetDefaultNameForKeynoteLegend, + nameof(ViewSchedule.GetDefaultNameForNoteBlock) => ResolveGetDefaultNameForNoteBlock, + nameof(ViewSchedule.GetDefaultNameForRevisionSchedule) => ResolveGetDefaultNameForRevisionSchedule, + nameof(ViewSchedule.GetDefaultNameForSheetList) => ResolveGetDefaultNameForSheetList, + nameof(ViewSchedule.GetDefaultNameForViewList) => ResolveGetDefaultNameForViewList, + nameof(ViewSchedule.GetValidFamiliesForNoteBlock) => ResolveGetValidFamiliesForNoteBlock, + nameof(ViewSchedule.RefreshData) => Variants.Disabled, +#if REVIT2022_OR_GREATER + nameof(ViewSchedule.GetScheduleInstances) => ResolveScheduleInstances, + nameof(ViewSchedule.GetSegmentHeight) => ResolveSegmentHeight, +#endif + _ => null + }; + + IVariant ResolveStripedRowsColor() + { + var patterns = Enum.GetValues(typeof(StripedRowPattern)); + var variants = Variants.Values(patterns.Length); + + foreach (StripedRowPattern pattern in patterns) + { + variants.Add(viewSchedule.GetStripedRowsColor(pattern), pattern.ToString()); + } + + return variants.Consume(); + } + + IVariant ResolveValidTextTypeId() + { + var types = viewSchedule.Document.EnumerateTypes().ToArray(); + var variants = Variants.Values(types.Length); + + foreach (var type in types) + { + var result = viewSchedule.IsValidTextTypeId(type.Id); + variants.Add(result, $"{type.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveDefaultNameForKeySchedule() + { + var categories = ViewSchedule.GetValidCategoriesForKeySchedule(); + var variants = Variants.Values(categories.Count); + foreach (var categoryId in categories) + { + variants.Add(ViewSchedule.GetDefaultNameForKeySchedule(viewSchedule.Document, categoryId)); + } + + return variants.Consume(); + } + + IVariant ResolveDefaultNameForMaterialTakeoff() + { + var categories = ViewSchedule.GetValidCategoriesForMaterialTakeoff(); + var variants = Variants.Values(categories.Count); + foreach (var categoryId in categories) + { + variants.Add(ViewSchedule.GetDefaultNameForMaterialTakeoff(viewSchedule.Document, categoryId)); + } + + return variants.Consume(); + } + + IVariant ResolveDefaultNameForSchedule() + { + var categories = ViewSchedule.GetValidCategoriesForSchedule(); + var areas = viewSchedule.Document.EnumerateInstances().ToArray(); + var variants = Variants.Values(categories.Count + areas.Length); + var areaId = new ElementId(BuiltInCategory.OST_Areas); + foreach (var categoryId in categories) + { + if (categoryId == areaId) + { + foreach (var area in areas) + { + variants.Add(ViewSchedule.GetDefaultNameForSchedule(viewSchedule.Document, categoryId, area.Id)); + } + } + else + { + variants.Add(ViewSchedule.GetDefaultNameForSchedule(viewSchedule.Document, categoryId)); + } + } + + return variants.Consume(); + } + + IVariant ResolveDefaultParameterNameForKeySchedule() + { + var categories = ViewSchedule.GetValidCategoriesForKeySchedule(); + var variants = Variants.Values(categories.Count); + var areaId = new ElementId(BuiltInCategory.OST_Areas); + foreach (var categoryId in categories) + { + if (categoryId == areaId) continue; + variants.Add(ViewSchedule.GetDefaultParameterNameForKeySchedule(viewSchedule.Document, categoryId)); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidCategoryForKeySchedule() + { + var categories = viewSchedule.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = ViewSchedule.IsValidCategoryForKeySchedule(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidCategoryForMaterialTakeoff() + { + var categories = viewSchedule.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = ViewSchedule.IsValidCategoryForMaterialTakeoff(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + + IVariant ResolveIsValidCategoryForSchedule() + { + var categories = viewSchedule.Document.Settings.Categories; + var variants = Variants.Values(categories.Size); + foreach (Category category in categories) + { + var result = ViewSchedule.IsValidCategoryForSchedule(category.Id); + variants.Add(result, $"{category.Name}: {result}"); + } + + return variants.Consume(); + } + +#if REVIT2022_OR_GREATER + IVariant ResolveScheduleInstances() + { + var count = viewSchedule.GetSegmentCount(); + var variants = Variants.Values>(count); + + for (var i = -1; i < count; i++) + { + variants.Add(viewSchedule.GetScheduleInstances(i)); + } + + return variants.Consume(); + } + + IVariant ResolveSegmentHeight() + { + var count = viewSchedule.GetSegmentCount(); + var variants = Variants.Values(count); + + for (var i = 0; i < count; i++) + { + variants.Add(viewSchedule.GetSegmentHeight(i)); + } + + return variants.Consume(); + } +#endif + IVariant ResolveGetDefaultNameForKeynoteLegend() + { + return Variants.Value(ViewSchedule.GetDefaultNameForKeynoteLegend(viewSchedule.Document)); + } + + IVariant ResolveGetDefaultNameForNoteBlock() + { + return Variants.Value(ViewSchedule.GetDefaultNameForNoteBlock(viewSchedule.Document)); + } + + IVariant ResolveGetDefaultNameForRevisionSchedule() + { + return Variants.Value(ViewSchedule.GetDefaultNameForRevisionSchedule(viewSchedule.Document)); + } + + IVariant ResolveGetDefaultNameForSheetList() + { + return Variants.Value(ViewSchedule.GetDefaultNameForSheetList(viewSchedule.Document)); + } + + IVariant ResolveGetDefaultNameForViewList() + { + return Variants.Value(ViewSchedule.GetDefaultNameForViewList(viewSchedule.Document)); + } + + IVariant ResolveGetValidFamiliesForNoteBlock() + { + return Variants.Value(ViewSchedule.GetValidFamiliesForNoteBlock(viewSchedule.Document)); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/WireDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/WireDescriptor.cs new file mode 100644 index 000000000..a586678f3 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/WireDescriptor.cs @@ -0,0 +1,55 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using Autodesk.Revit.DB.Electrical; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class WireDescriptor(Wire wire) : ElementDescriptor(wire) +{ + public override Func? Resolve(string target, ParameterInfo[] parameters) + { + return target switch + { + nameof(Wire.GetVertex) => ResolveVertex, + _ => null + }; + + IVariant ResolveVertex() + { + var capacity = wire.NumberOfVertices; + var variants = Variants.Values(capacity); + + for (var i = 0; i < capacity; i++) + { + variants.Add(wire.GetVertex(i)); + } + + return variants.Consume(); + } + } + + public override void RegisterExtensions(IExtensionManager manager) + { + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/WorksetDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/WorksetDescriptor.cs new file mode 100644 index 000000000..cdd4616ad --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/WorksetDescriptor.cs @@ -0,0 +1,32 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class WorksetDescriptor : Descriptor, IDescriptorCollector +{ + public WorksetDescriptor(Workset workset) + { + Name = workset.Name; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Api.cs b/source/RevitLookup/Core/Decomposition/Descriptors/WorksetTableDescriptor.cs similarity index 53% rename from source/RevitLookup/Core/Engine/DescriptorBuilder.Api.cs rename to source/RevitLookup/Core/Decomposition/Descriptors/WorksetTableDescriptor.cs index 0bc0fe1f3..0156d257d 100644 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Api.cs +++ b/source/RevitLookup/Core/Decomposition/Descriptors/WorksetTableDescriptor.cs @@ -18,37 +18,33 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Core.Engine; +using System.Reflection; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; -public sealed partial class DescriptorBuilder +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class WorksetTableDescriptor : Descriptor, IDescriptorResolver { - public static IList Build(Type type) + public Func? Resolve(string target, ParameterInfo[] parameters) { - var builder = new DescriptorBuilder + return target switch { - _obj = null, - Context = Nice3point.Revit.Toolkit.Context.ActiveDocument + nameof(WorksetTable.GetWorkset) when parameters?.Length == 1 && parameters[0].ParameterType == typeof(WorksetId) => ResolveGetWorkset, + _ => null }; - return builder.BuildStaticObject(type); - } - - public static IList Build(object obj, Document context) - { - if (obj is null) return Array.Empty(); + IVariant ResolveGetWorkset() + { + var worksets = new FilteredWorksetCollector(Context.ActiveDocument).ToWorksets(); + var variants = Variants.Values(worksets.Count); - var builder = new DescriptorBuilder(); + foreach (var workset in worksets) + { + variants.Add(workset); + } - switch (obj) - { - case Type staticObjectType: - builder._obj = null; - builder.Context = context; - return builder.BuildStaticObject(staticObjectType); - default: - builder._obj = obj; - builder.Context = context; - return builder.BuildInstanceObject(obj.GetType()); + return variants.Consume(); } } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/Descriptors/XyzDescriptor.cs b/source/RevitLookup/Core/Decomposition/Descriptors/XyzDescriptor.cs new file mode 100644 index 000000000..345659192 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/Descriptors/XyzDescriptor.cs @@ -0,0 +1,69 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Controls; +using System.Windows.Input; +using LookupEngine.Abstractions.Decomposition; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Configuration; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Visualization; + +namespace RevitLookup.Core.Decomposition.Descriptors; + +public sealed class XyzDescriptor : Descriptor, IContextMenuConnector +{ + private readonly XYZ _point; + + public XyzDescriptor(XYZ point) + { + _point = point; + Name = point.ToString(); + } + + public void RegisterMenu(ContextMenu contextMenu, IServiceProvider serviceProvider) + { + contextMenu.AddMenuItem("VisualizeMenuItem") + .SetAvailability(!_point.IsUnitLength()) + .SetCommand(_point, VisualizeXyz) + .SetShortcut(Key.F8); + + async Task VisualizeXyz(XYZ point) + { + if (Context.ActiveUiDocument is null) return; + + try + { + var dialog = serviceProvider.GetRequiredService(); + await dialog.ShowDialogAsync(point); + } + catch (Exception exception) + { + var logger = serviceProvider.GetRequiredService>(); + var notificationService = serviceProvider.GetRequiredService(); + + logger.LogError(exception, "Visualize XYZ error"); + notificationService.ShowError("Visualization error", exception); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/DescriptorsMap.cs b/source/RevitLookup/Core/Decomposition/DescriptorsMap.cs new file mode 100644 index 000000000..c6618a8c6 --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/DescriptorsMap.cs @@ -0,0 +1,178 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using System.ComponentModel; +using System.Windows; +using System.Windows.Threading; +using Autodesk.Revit.DB.Electrical; +using Autodesk.Revit.DB.ExtensibleStorage; +using Autodesk.Revit.DB.ExternalService; +using Autodesk.Revit.DB.Lighting; +using Autodesk.Revit.DB.Mechanical; +using Autodesk.Revit.DB.Plumbing; +using Autodesk.Revit.DB.Structure; +using Autodesk.Revit.DB.Visual; +using Autodesk.Revit.UI; +using Autodesk.Windows; +using LookupEngine.Abstractions.Decomposition; +using LookupEngine.Descriptors; +using RevitLookup.Core.Decomposition.Descriptors; +using EnumerableDescriptor = RevitLookup.Core.Decomposition.Descriptors.EnumerableDescriptor; +using RevitApplication = Autodesk.Revit.ApplicationServices.Application; +using RibbonItem = Autodesk.Revit.UI.RibbonItem; +using RibbonPanel = Autodesk.Revit.UI.RibbonPanel; + +namespace RevitLookup.Core.Decomposition; + +public static class DescriptorsMap +{ + /// + /// Search for a descriptor by approximate or exact match + /// + /// + /// Exact search is necessary for the reflection engine, to add extensions and resolve conflicts when calling methods and properties. Type is not null

+ /// An approximate search is needed to describe the object, which is displayed to the user. Type is null + /// + public static Descriptor FindDescriptor(object? obj, Type? type) + { + return obj switch + { + //System + string value when type is null || type == typeof(string) => new StringDescriptor(value), + bool value when type is null || type == typeof(bool) => new BooleanDescriptor(value), + IEnumerable value => new EnumerableDescriptor(value), + Exception value when type is null || type == typeof(Exception) => new ExceptionDescriptor(value), + + //Root + ElementId value when type is null || type == typeof(ElementId) => new ElementIdDescriptor(value), + GuidEnum value when type is null || type == typeof(GuidEnum) => new GuidEnumDescriptor(value), + Definition value when type is null || type == typeof(Definition) => new DefinitionDescriptor(value), + XYZ value when type is null || type == typeof(XYZ) => new XyzDescriptor(value), + + //Enumerator + DefinitionBindingMapIterator value => new DefinitionBindingMapIteratorDescriptor(value), + // IEnumerator value => new EnumeratorDescriptor(value), + + //APIObjects + BoundingBoxXYZ value when type is null || type == typeof(BoundingBoxXYZ) => new BoundingBoxXyzDescriptor(value), + Category value when type is null || type == typeof(Category) => new CategoryDescriptor(value), + Parameter value when type is null || type == typeof(Parameter) => new ParameterDescriptor(value), + FamilyParameter value when type is null || type == typeof(FamilyParameter) => new FamilyParameterDescriptor(value), + Reference value when type is null || type == typeof(Reference) => new ReferenceDescriptor(value), + Color value when type is null || type == typeof(Color) => new ColorDescriptor(value), + Curve value when type is null || type == typeof(Curve) => new CurveDescriptor(value), + Edge value when type is null || type == typeof(Edge) => new EdgeDescriptor(value), + Solid value when type is null || type == typeof(Solid) => new SolidDescriptor(value), + Mesh value when type is null || type == typeof(Mesh) => new MeshDescriptor(value), + CylindricalFace value when type is null || type == typeof(CylindricalFace) => new CylindricalFaceDescriptor(value), + Face value when type is null || type == typeof(Face) => new FaceDescriptor(value), + City value when type is null || type == typeof(City) => new CityDescriptor(value), + PaperSize value when type is null || type == typeof(PaperSize) => new PaperSizeDescriptor(value), + PrintManager value when type is null || type == typeof(PrintManager) => new PrintManagerDescriptor(value), + DefinitionGroup value when type is null || type == typeof(DefinitionGroup) => new DefinitionGroupDescriptor(value), + FamilyManager value when type is null || type == typeof(FamilyManager) => new FamilyManagerDescriptor(value), + MEPSection value when type is null || type == typeof(MEPSection) => new MepSectionDescriptor(value), + LocationCurve value when type is null || type == typeof(LocationCurve) => new LocationCurveDescriptor(value), + CurtainGrid value when type is null || type == typeof(CurtainGrid) => new CurtainGridDescriptor(value), + APIObject when type is null || type == typeof(APIObject) => new ApiObjectDescriptor(), + + //Elements + Panel value when type is null || type == typeof(Panel) => new PanelDescriptor(value), + FamilyInstance value when type is null || type == typeof(FamilyInstance) => new FamilyInstanceDescriptor(value), + Family value when type is null || type == typeof(Family) => new FamilyDescriptor(value), + ViewSchedule value when type is null || type == typeof(ViewSchedule) => new ViewScheduleDescriptor(value), + TableView value when type is null || type == typeof(TableView) => new TableViewDescriptor(value), + View value when type is null || type == typeof(View) => new ViewDescriptor(value), + Wire value when type is null || type == typeof(Wire) => new WireDescriptor(value), + Pipe value when type is null || type == typeof(Pipe) => new PipeDescriptor(value), + HostObject value when type is null || type == typeof(HostObject) => new HostObjectDescriptor(value), + ElevationMarker value when type is null || type == typeof(ElevationMarker) => new ElevationMarkerDescriptor(value), + RevitLinkType value when type is null || type == typeof(RevitLinkType) => new RevitLinkTypeDescriptor(value), + AnalyticalLinkType value when type is null || type == typeof(AnalyticalLinkType) => new AnalyticalLinkTypeDescriptor(value), + SpatialElement value when type is null || type == typeof(SpatialElement) => new SpatialElementDescriptor(value), + SunAndShadowSettings value when type is null || type == typeof(SunAndShadowSettings) => new SunAndShadowSettingsDescriptor(value), + IndependentTag value when type is null || type == typeof(IndependentTag) => new IndependentTagDescriptor(value), + MEPSystem value when type is null || type == typeof(MEPSystem) => new MepSystemDescriptor(value), + BasePoint value when type is null || type == typeof(BasePoint) => new BasePointDescriptor(value), + InternalOrigin value when type is null || type == typeof(InternalOrigin) => new InternalOriginDescriptor(value), + StructuralSettings value when type is null || type == typeof(StructuralSettings) => new StructuralSettingsDescriptor(value), + AreaVolumeSettings value when type is null || type == typeof(AreaVolumeSettings) => new AreaVolumeSettingsDescriptor(value), + CurveElement value when type is null || type == typeof(CurveElement) => new CurveElementDescriptor(value), + DatumPlane value when type is null || type == typeof(DatumPlane) => new DatumPlaneDescriptor(value), + Part value when type is null || type == typeof(Part) => new PartDescriptor(value), + PartMaker value when type is null || type == typeof(PartMaker) => new PartMakerDescriptor(value), +#if REVIT2022_OR_GREATER + RevisionNumberingSequence value when type is null || type == typeof(RevisionNumberingSequence) => new RevisionNumberingSequenceDescriptor(value), +#endif + Element value when type is null || type == typeof(Element) => new ElementDescriptor(value), + + //IDisposables + Document value when type is null || type == typeof(Document) => new DocumentDescriptor(value), + PlanViewRange value when type is null || type == typeof(PlanViewRange) => new PlanViewRangeDescriptor(value), + ForgeTypeId value when type is null || type == typeof(ForgeTypeId) => new ForgeTypeIdDescriptor(value), + Entity value when type is null || type == typeof(Entity) => new EntityDescriptor(value), + Field value when type is null || type == typeof(Field) => new FieldDescriptor(value), + Schema value when type is null || type == typeof(Schema) => new SchemaDescriptor(value), + FailureMessage value when type is null || type == typeof(FailureMessage) => new FailureMessageDescriptor(value), + UpdaterInfo value when type is null || type == typeof(UpdaterInfo) => new UpdaterInfoDescriptor(value), + ExternalService value when type is null || type == typeof(ExternalService) => new ExternalServiceDescriptor(value), + LightFamily value when type is null || type == typeof(LightFamily) => new LightFamilyDescriptor(value), + RevitApplication value when type is null || type == typeof(RevitApplication) => new ApplicationDescriptor(value), + UIApplication when type is null || type == typeof(UIApplication) => new UiApplicationDescriptor(), + PerformanceAdviser value when type is null || type == typeof(PerformanceAdviser) => new PerformanceAdviserDescriptor(value), + SchedulableField value when type is null || type == typeof(SchedulableField) => new SchedulableFieldDescriptor(value), + CompoundStructureLayer value when type is null || type == typeof(CompoundStructureLayer) => new CompoundStructureLayerDescriptor(value), + Workset value when type is null || type == typeof(Workset) => new WorksetDescriptor(value), + WorksetTable when type is null || type == typeof(WorksetTable) => new WorksetTableDescriptor(), + BoundarySegment value when type is null || type == typeof(BoundarySegment) => new BoundarySegmentDescriptor(value), + AssetProperties value when type is null || type == typeof(AssetProperties) => new AssetPropertiesDescriptor(value), + AssetProperty value when type is null || type == typeof(AssetProperty) => new AssetPropertyDescriptor(value), + ConnectorManager value when type is null || type == typeof(ConnectorManager) => new ConnectorManagerDescriptor(value), + ScheduleDefinition value when type is null || type == typeof(ScheduleDefinition) => new ScheduleDefinitionDescriptor(value), + TableData value when type is null || type == typeof(TableData) => new TableDataDescriptor(value), + TableSectionData value when type is null || type == typeof(TableSectionData) => new TableSectionDataDescriptor(value), + FamilySizeTableManager value when type is null || type == typeof(FamilySizeTableManager) => new FamilySizeTableManagerDescriptor(value), + FamilySizeTable value when type is null || type == typeof(FamilySizeTable) => new FamilySizeTableDescriptor(value), + FamilySizeTableColumn value when type is null || type == typeof(FamilySizeTableColumn) => new FamilySizeTableColumnDescriptor(value), + CompoundStructure value when type is null || type == typeof(CompoundStructure) => new CompoundStructureDescriptor(value), +#if REVIT2024_OR_GREATER + EvaluatedParameter value when type is null || type == typeof(EvaluatedParameter) => new EvaluatedParameterDescriptor(value), +#endif + IDisposable when type is null || type == typeof(IDisposable) => new DisposableDescriptor(), //Faster then obj.GetType().Namespace == "Autodesk.Revit.DB" + + //Media + System.Windows.Media.Color value when type is null || type == typeof(System.Windows.Media.Color) => new ColorMediaDescriptor(value), + + //ComponentManager + UIElement => new UiElementDescriptor(), + DispatcherObject => new DependencyObjectDescriptor(), + RibbonItem value => new RibbonItemDescriptor(value), + RibbonPanel value => new RibbonPanelDescriptor(value), + Autodesk.Windows.RibbonItem value => new RibbonItemDescriptor(value), + Autodesk.Windows.RibbonPanel value => new RibbonPanelDescriptor(value), + RibbonTab value => new RibbonTabDescriptor(value), + INotifyPropertyChanged => new UiObjectDescriptor(), + + //Unknown + _ => new ObjectDescriptor(obj) + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Decomposition/RevitObjectsCollector.cs b/source/RevitLookup/Core/Decomposition/RevitObjectsCollector.cs new file mode 100644 index 000000000..7e51be09f --- /dev/null +++ b/source/RevitLookup/Core/Decomposition/RevitObjectsCollector.cs @@ -0,0 +1,220 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using Autodesk.Revit.DB.ExtensibleStorage; +using Autodesk.Revit.DB.ExternalService; +using Autodesk.Revit.UI.Selection; +using Autodesk.Windows; +using RevitLookup.Abstractions.Models.Decomposition; + +namespace RevitLookup.Core.Decomposition; + +public static class RevitObjectsCollector +{ + public static IEnumerable GetObjects(KnownDecompositionObject decompositionObject) + { + return decompositionObject switch + { + KnownDecompositionObject.View => FindView(), + KnownDecompositionObject.Document => FindDocument(), + KnownDecompositionObject.Application => FindApplication(), + KnownDecompositionObject.UiApplication => FindUiApplication(), + KnownDecompositionObject.UiControlledApplication => FindUiControlledApplication(), + KnownDecompositionObject.Database => FindDatabase(), + KnownDecompositionObject.DependentElements => FindDependentElements(), + KnownDecompositionObject.Selection => FindSelection(), + KnownDecompositionObject.Face => FindFace(), + KnownDecompositionObject.Edge => FindEdge(), + KnownDecompositionObject.SubElement => FindSubElement(), + KnownDecompositionObject.Point => FindPoint(), + KnownDecompositionObject.LinkedElement => FindLinkedElement(), + KnownDecompositionObject.ComponentManager => FindComponentManager(), + KnownDecompositionObject.PerformanceAdviser => FindPerformanceAdviser(), + KnownDecompositionObject.UpdaterRegistry => FindUpdaterRegistry(), + KnownDecompositionObject.Services => FindServices(), + KnownDecompositionObject.Schemas => FindSchemas(), + _ => throw new ArgumentOutOfRangeException(nameof(decompositionObject), decompositionObject, null) + }; + } + + private static IEnumerable FindView() + { + return new object?[] {Context.ActiveView}; + } + + private static IEnumerable FindDocument() + { + return new object?[] {Context.ActiveDocument}; + } + + private static IEnumerable FindApplication() + { + return new object?[] {Context.Application}; + } + + private static IEnumerable FindUiApplication() + { + return new object?[] {Context.UiApplication}; + } + + private static IEnumerable FindUiControlledApplication() + { + return new object[] {Context.UiControlledApplication}; + } + + private static IEnumerable FindEdge() + { + return FindObject(ObjectType.Edge); + } + + private static IEnumerable FindFace() + { + return FindObject(ObjectType.Face); + } + + private static IEnumerable FindSubElement() + { + return FindObject(ObjectType.Subelement); + } + + private static IEnumerable FindPoint() + { + return FindObject(ObjectType.PointOnElement); + } + + private static IEnumerable FindLinkedElement() + { + return FindObject(ObjectType.LinkedElement); + } + + private static IEnumerable FindSelection() + { + var activeUiDocument = Context.ActiveUiDocument; + if (activeUiDocument is null) + { + return Array.Empty(); + } + + var selectedIds = activeUiDocument.Selection.GetElementIds(); + if (selectedIds.Count > 0) + { + return activeUiDocument.Document + .GetElements(selectedIds) + .WherePasses(new ElementIdSetFilter(selectedIds)) + .ToArray(); + } + + return activeUiDocument.Document + .GetElements(activeUiDocument.ActiveView.Id) + .ToArray(); + } + + private static IEnumerable FindDatabase() + { + var activeDocument = Context.ActiveDocument!; + var elementTypes = activeDocument.GetElements().WhereElementIsElementType(); + var elementInstances = activeDocument.GetElements().WhereElementIsNotElementType(); + return elementTypes + .UnionWith(elementInstances) + .ToArray(); + } + + private static IEnumerable FindDependentElements() + { + var selectedIds = Context.ActiveUiDocument!.Selection.GetElementIds(); + if (selectedIds.Count == 0) return Array.Empty(); + + var elements = new List(); + var activeDocument = Context.ActiveDocument!; + var selectedElements = activeDocument.GetElements(selectedIds).WhereElementIsNotElementType(); + + foreach (var selectedElement in selectedElements) + { + var dependentElements = selectedElement.GetDependentElements(null); + foreach (var dependentElement in dependentElements) elements.Add(dependentElement); + } + + return activeDocument.GetElements() + .WherePasses(new ElementIdSetFilter(elements)) + .ToArray(); + } + + private static IEnumerable FindComponentManager() + { + return new object?[] {typeof(ComponentManager)}; + } + + private static IEnumerable FindPerformanceAdviser() + { + return new object?[] {PerformanceAdviser.GetPerformanceAdviser()}; + } + + private static IEnumerable FindUpdaterRegistry() + { + return UpdaterRegistry.GetRegisteredUpdaterInfos(); + } + + private static IEnumerable FindSchemas() + { + return Schema.ListSchemas(); + } + + private static IEnumerable FindServices() + { + return ExternalServiceRegistry.GetServices(); + } + + private static IEnumerable FindObject(ObjectType objectType) + { + var activeUiDocument = Context.ActiveUiDocument; + if (activeUiDocument is null) + { + return Array.Empty(); + } + + var reference = activeUiDocument.Selection.PickObject(objectType); + + object element; + switch (objectType) + { + case ObjectType.Edge: + case ObjectType.Face: + element = activeUiDocument.Document.GetElement(reference).GetGeometryObjectFromReference(reference); + break; + case ObjectType.Element: + case ObjectType.Subelement: + element = activeUiDocument.Document.GetElement(reference); + break; + case ObjectType.PointOnElement: + element = reference.GlobalPoint; + break; + case ObjectType.LinkedElement: + var revitLinkInstance = reference.ElementId.ToElement(activeUiDocument.Document)!; + element = revitLinkInstance.GetLinkDocument().GetElement(reference.LinkedElementId); + break; + case ObjectType.Nothing: + default: + throw new NotSupportedException(); + } + + return new[] {element}; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Build.cs b/source/RevitLookup/Core/Engine/DescriptorBuilder.Build.cs deleted file mode 100644 index f8056a952..000000000 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Build.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Reflection; -using RevitLookup.Core.Utils; - -namespace RevitLookup.Core.Engine; - -public sealed partial class DescriptorBuilder -{ - private IList BuildInstanceObject(Type type) - { - var types = GetTypeHierarchy(type); - - for (var i = types.Count - 1; i >= 0; i--) - { - _type = types[i]; - _currentDescriptor = DescriptorUtils.FindSuitableDescriptor(_obj, _type); - - var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; - if (_settings.IncludeStatic) flags |= BindingFlags.Static; - if (_settings.IncludePrivate) flags |= BindingFlags.NonPublic; - - AddProperties(flags); - AddMethods(flags); - AddFields(flags); - AddEvents(flags); - AddExtensions(); - - _depth--; - } - - AddEnumerableItems(); - - return _descriptors; - } - - private List GetTypeHierarchy(Type type) - { - var types = new List(); - while (type.BaseType is not null) - { - types.Add(type); - type = type.BaseType; - } - - if (_settings.IncludeRootHierarchy) types.Add(type); - - return types; - } - - private IList BuildStaticObject(Type type) - { - _type = type; - - var flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; - if (_settings.IncludePrivate) flags |= BindingFlags.NonPublic; - - AddProperties(flags); - AddMethods(flags); - AddFields(flags); - - return _descriptors; - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Events.cs b/source/RevitLookup/Core/Engine/DescriptorBuilder.Events.cs deleted file mode 100644 index 845b17109..000000000 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Events.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using RevitLookup.Core.Utils; - -namespace RevitLookup.Core.Engine; - -public sealed partial class DescriptorBuilder -{ - private void AddEvents(BindingFlags bindingFlags) - { - if (!_settings.IncludeEvents) return; - - var members = _type.GetEvents(bindingFlags); - foreach (var member in members) - { - WriteDescriptor(member, DescriptorUtils.MakeGenericTypeName(member.EventHandlerType), null); - } - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.Write.cs b/source/RevitLookup/Core/Engine/DescriptorBuilder.Write.cs deleted file mode 100644 index 3efe5e2d5..000000000 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.Write.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Reflection; -using RevitLookup.Core.ComponentModel.Descriptors; -using RevitLookup.Core.Enums; -using RevitLookup.Core.Utils; - -namespace RevitLookup.Core.Engine; - -public sealed partial class DescriptorBuilder -{ - private void WriteDescriptor(object value) - { - var descriptor = new ObjectDescriptor - { - Depth = _depth, - Value = EvaluateValue(value), - TypeFullName = DescriptorUtils.MakeGenericFullTypeName(_type), - MemberAttributes = MemberAttributes.Property, - Type = DescriptorUtils.MakeGenericTypeName(_type) - }; - - descriptor.Name = descriptor.Value.Descriptor.Type; - _descriptors.Add(descriptor); - } - - private void WriteDescriptor(string name, object value) - { - var descriptor = new ObjectDescriptor - { - Depth = _depth, - Name = name, - Value = EvaluateValue(value), - TypeFullName = DescriptorUtils.MakeGenericFullTypeName(_type), - MemberAttributes = MemberAttributes.Extension, - Type = DescriptorUtils.MakeGenericTypeName(_type), - ComputationTime = _clockDiagnoser.GetElapsed().TotalMilliseconds, - AllocatedBytes = _memoryDiagnoser.GetAllocatedBytes() - }; - - _descriptors.Add(descriptor); - } - - private void WriteDescriptor(MemberInfo member, object value, ParameterInfo[] parameters) - { - var descriptor = new ObjectDescriptor - { - Depth = _depth, - TypeFullName = DescriptorUtils.MakeGenericFullTypeName(_type), - Value = EvaluateValue(member, value), - Name = EvaluateName(member, parameters), - MemberAttributes = EvaluateAttributes(member), - Type = DescriptorUtils.MakeGenericTypeName(_type), - ComputationTime = _clockDiagnoser.GetElapsed().TotalMilliseconds, - AllocatedBytes = _memoryDiagnoser.GetAllocatedBytes() - }; - - _descriptors.Add(descriptor); - } - - private SnoopableObject EvaluateValue(MemberInfo member, object value) - { - var snoopableObject = new SnoopableObject(value, Context); - SnoopUtils.Redirect(member.Name, snoopableObject); - return snoopableObject; - } - - private SnoopableObject EvaluateValue(object value) - { - var snoopableObject = new SnoopableObject(value, Context); - SnoopUtils.Redirect(snoopableObject); - return snoopableObject; - } - - private static string EvaluateName(MemberInfo member, [CanBeNull] ParameterInfo[] types) - { - if (types is null) return member.Name; - if (types.Length == 0) return member.Name; - - var parameterNames = types.Select(info => - { - return info.ParameterType.IsByRef switch - { - true => $"ref {DescriptorUtils.MakeGenericTypeName(info.ParameterType).Replace("&", string.Empty)}", - _ => DescriptorUtils.MakeGenericTypeName(info.ParameterType) - }; - }); - - var parameters = string.Join(", ", parameterNames); - return $"{member.Name} ({parameters})"; - } - - private static MemberAttributes EvaluateAttributes(MemberInfo member) - { - return member switch - { - MethodInfo info => GetModifiers(MemberAttributes.Method, info.Attributes), - PropertyInfo info => GetModifiers(MemberAttributes.Property, info.CanRead ? info.GetMethod!.Attributes : info.SetMethod!.Attributes), - FieldInfo info => GetModifiers(MemberAttributes.Field, info.Attributes), - EventInfo info => GetModifiers(MemberAttributes.Event, info.AddMethod!.Attributes), - _ => throw new ArgumentOutOfRangeException(nameof(member)) - }; - } - - private static MemberAttributes GetModifiers(MemberAttributes attributes, MethodAttributes methodAttributes) - { - if ((methodAttributes & MethodAttributes.Static) != 0) attributes |= MemberAttributes.Static; - if ((methodAttributes & MethodAttributes.Private) != 0) attributes |= MemberAttributes.Private; - return attributes; - } - - private static MemberAttributes GetModifiers(MemberAttributes attributes, FieldAttributes fieldAttributes) - { - if ((fieldAttributes & FieldAttributes.Static) != 0) attributes |= MemberAttributes.Static; - if ((fieldAttributes & FieldAttributes.Private) != 0) attributes |= MemberAttributes.Private; - return attributes; - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Engine/DescriptorBuilder.cs b/source/RevitLookup/Core/Engine/DescriptorBuilder.cs deleted file mode 100644 index c9ee6ae16..000000000 --- a/source/RevitLookup/Core/Engine/DescriptorBuilder.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using RevitLookup.Core.Diagnostic; -using RevitLookup.Models.Settings; -using RevitLookup.Services.Contracts; - -namespace RevitLookup.Core.Engine; - -public sealed partial class DescriptorBuilder -{ - private readonly List _descriptors; - private readonly GeneralSettings _settings; - private Descriptor _currentDescriptor; - private object _obj; - private Type _type; - private int _depth; - - private readonly ClockDiagnoser _clockDiagnoser = new(); - private readonly MemoryDiagnoser _memoryDiagnoser = new(); - - private DescriptorBuilder() - { - _descriptors = new List(16); - _settings = Host.GetService().GeneralSettings; - } - - public Document Context { get; private set; } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Objects/Descriptor.cs b/source/RevitLookup/Core/Objects/Descriptor.cs deleted file mode 100644 index 4d9e286c0..000000000 --- a/source/RevitLookup/Core/Objects/Descriptor.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using RevitLookup.Core.Enums; - -namespace RevitLookup.Core.Objects; - -public abstract class Descriptor -{ - public int Depth { get; set; } - public string TypeFullName { get; set; } - public string Type { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public double ComputationTime { get; set; } - public long AllocatedBytes { get; set; } - public MemberAttributes MemberAttributes { get; set; } - public SnoopableObject Value { get; set; } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Objects/SnoopableObject.cs b/source/RevitLookup/Core/Objects/SnoopableObject.cs deleted file mode 100644 index abaa839ed..000000000 --- a/source/RevitLookup/Core/Objects/SnoopableObject.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using RevitLookup.Core.Engine; -using RevitLookup.Core.Utils; - -namespace RevitLookup.Core.Objects; - -public sealed class SnoopableObject -{ - private IList _members; - - public SnoopableObject(Type type) - { - Object = type; - Descriptor = DescriptorUtils.FindSuitableDescriptor(type); - } - - public SnoopableObject(object obj) - { - Object = obj; - Context = ContextUtils.FindSuitableContext(obj); - Descriptor = DescriptorUtils.FindSuitableDescriptor(obj); - } - - public SnoopableObject(object obj, Document context) - { - Object = obj; - Context = ContextUtils.FindSuitableContext(obj, context); - Descriptor = DescriptorUtils.FindSuitableDescriptor(obj); - } - - public object Object { get; set; } - public Descriptor Descriptor { get; set; } - public Document Context { get; } - - public IList GetMembers() - { - return _members = DescriptorBuilder.Build(Object, Context); - } - - public async Task> GetMembersAsync() - { - return _members = await RevitShell.ExternalDescriptorHandler.RaiseAsync(_ => DescriptorBuilder.Build(Object, Context)); - } - - public async Task> GetCachedMembersAsync() - { - return _members ?? await GetMembersAsync(); - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Objects/Variants.cs b/source/RevitLookup/Core/Objects/Variants.cs deleted file mode 100644 index 914ed1107..000000000 --- a/source/RevitLookup/Core/Objects/Variants.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using System.Collections; - -namespace RevitLookup.Core.Objects; - -/// -/// Provides methods for creating variant collections -/// -/// Variants are provided for IDescriptorResolver -public static class Variants -{ - /// - /// Creates a variant collection with a single value - /// - /// A variant collection containing the specified value - public static IVariants Single(T value) - { - return new Variants(1).Add(value); - } - - /// - /// Creates a variant collection with a single value and description - /// - /// A variant collection containing the specified value - public static IVariants Single(T value, string description) - { - return new Variants(1).Add(value, description); - } - - /// - /// Creates an empty variant collection - /// - /// An empty variant collection - /// An empty collection is returned when there are no solutions for a member - public static IVariants Empty() - { - return new Variants(0); - } - - /// - /// A variant that disables the member calculation - /// - public static Func Disabled { get; } = () => new Variants(1).Add(new InvalidOperationException("Member execution disabled")); -} - -/// -/// Represents a collection of variants -/// -/// The type of the variants -/// The initial variants capacity. Required for atomic performance optimizations -public sealed class Variants(int capacity) : IVariants -{ - private readonly Queue _items = new(capacity); - - /// - /// Gets the number of variants - /// - public int Count => _items.Count; - - /// - /// Adds a new variant - /// - /// The variant collection with a new value - public Variants Add(T result) - { - if (result is null) return this; - if (result is ICollection {Count: 0}) return this; - - _items.Enqueue(new Variant - { - Object = result - }); - - return this; - } - - /// - /// Adds a new variant with description - /// - /// The variant collection with a new value - public Variants Add(T result, string description) - { - if (result is null) return this; - if (result is ICollection {Count: 0}) return this; - - _items.Enqueue(new Variant - { - Object = result, - Description = description - }); - - return this; - } - - /// - /// Returns a single value if exists - /// - /// Single variant - /// Used for internal purposes only and to display a single result instead of a list - public Variant Single() - { - if (_items.Count != 1) - { - throw new IndexOutOfRangeException("Variants contains more than one element or variants is empty"); - } - - return _items.Peek(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - private Queue.Enumerator GetEnumerator() - { - return _items.GetEnumerator(); - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/RevitShell.API.cs b/source/RevitLookup/Core/RevitShell.API.cs new file mode 100644 index 000000000..4bc279de2 --- /dev/null +++ b/source/RevitLookup/Core/RevitShell.API.cs @@ -0,0 +1,139 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Reflection; +using System.Runtime.InteropServices; + +namespace RevitLookup.Core; + +public static partial class RevitShell +{ + public static Parameter GetBuiltinParameter(BuiltInParameter builtInParameter) + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + + var documentType = typeof(Document); + var parameterType = typeof(Parameter); + var assembly = Assembly.GetAssembly(parameterType)!; + var aDocumentType = assembly.GetType("ADocument")!; + var elementIdType = assembly.GetType("ElementId")!; + var elementIdIdType = elementIdType.GetField("", bindingFlags)!; + var getADocumentType = documentType.GetMethod("getADocument", bindingFlags)!; + var parameterCtorType = parameterType.GetConstructor(bindingFlags, null, [aDocumentType.MakePointerType(), elementIdType.MakePointerType()], null)!; + + var elementId = Activator.CreateInstance(elementIdType)!; + elementIdIdType.SetValue(elementId, builtInParameter); + + var handle = GCHandle.Alloc(elementId); + var elementIdPointer = GCHandle.ToIntPtr(handle); + Marshal.StructureToPtr(elementId, elementIdPointer, true); + + var parameter = (Parameter) parameterCtorType.Invoke([getADocumentType.Invoke(Context.ActiveDocument, null), elementIdPointer]); + handle.Free(); + + return parameter; + } + + public static Category GetBuiltinCategory(BuiltInCategory builtInCategory) + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + + var documentType = typeof(Document); + var categoryType = typeof(Category); + var assembly = Assembly.GetAssembly(categoryType)!; + var aDocumentType = assembly.GetType("ADocument")!; + var elementIdType = assembly.GetType("ElementId")!; + var elementIdIdType = elementIdType.GetField("", bindingFlags)!; + var getADocumentType = documentType.GetMethod("getADocument", bindingFlags)!; + var categoryCtorType = categoryType.GetConstructor(bindingFlags, null, [aDocumentType.MakePointerType(), elementIdType.MakePointerType()], null)!; + + var elementId = Activator.CreateInstance(elementIdType)!; + elementIdIdType.SetValue(elementId, builtInCategory); + + var handle = GCHandle.Alloc(elementId); + var elementIdPointer = GCHandle.ToIntPtr(handle); + Marshal.StructureToPtr(elementId, elementIdPointer, true); + + var category = (Category) categoryCtorType.Invoke([getADocumentType.Invoke(Context.ActiveDocument, null), elementIdPointer]); + handle.Free(); + + return category; + } + + public static string GetParameterValue(Parameter parameter) + { + return parameter.StorageType switch + { + StorageType.Integer => parameter.AsInteger().ToString(), + StorageType.Double => parameter.AsValueString(), + StorageType.String => parameter.AsString(), + StorageType.ElementId => parameter.AsElementId().ToString(), + StorageType.None => parameter.AsValueString(), + _ => parameter.AsValueString() + }; + } + + public static void UpdateParameterValue(Parameter parameter, string value) + { + var transaction = new Transaction(parameter.Element.Document); + transaction.Start("Set parameter value"); + + bool result; + switch (parameter.StorageType) + { + case StorageType.Integer: + result = int.TryParse(value, out var intValue); + if (!result) break; + + result = parameter.Set(intValue); + break; + case StorageType.Double: + result = parameter.SetValueString(value); + break; + case StorageType.String: + result = parameter.Set(value); + break; + case StorageType.ElementId: +#if REVIT2024_OR_GREATER + result = long.TryParse(value, out var idValue); +#else + result = int.TryParse(value, out var idValue); +#endif + if (!result) break; + + result = parameter.Set(new ElementId(idValue)); + break; + case StorageType.None: + default: + result = parameter.SetValueString(value); + break; + } + + if (result) + { + transaction.Commit(); + } + else + { + transaction.RollBack(); + throw new ArgumentException("Invalid parameter value"); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/RevitShell.Handlers.cs b/source/RevitLookup/Core/RevitShell.Handlers.cs new file mode 100644 index 000000000..f7c069e35 --- /dev/null +++ b/source/RevitLookup/Core/RevitShell.Handlers.cs @@ -0,0 +1,81 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Collections; +using Nice3point.Revit.Toolkit.External.Handlers; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Core; + +public static partial class RevitShell +{ + private static ActionEventHandler? _actionEventHandler; + private static AsyncEventHandler? _asyncEventHandler; + private static AsyncEventHandler? _asyncObjectHandler; + private static AsyncEventHandler>? _asyncObjectsHandler; + private static AsyncEventHandler>? _asyncMembersHandler; + private static AsyncEventHandler? _asyncCollectionHandler; + + public static ActionEventHandler ActionEventHandler + { + get => _actionEventHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _actionEventHandler = value; + } + + public static AsyncEventHandler AsyncEventHandler + { + get => _asyncEventHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _asyncEventHandler = value; + } + + public static AsyncEventHandler AsyncObjectHandler + { + get => _asyncObjectHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _asyncObjectHandler = value; + } + + public static AsyncEventHandler> AsyncObjectsHandler + { + get => _asyncObjectsHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _asyncObjectsHandler = value; + } + + public static AsyncEventHandler> AsyncMembersHandler + { + get => _asyncMembersHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _asyncMembersHandler = value; + } + + public static AsyncEventHandler AsyncCollectionHandler + { + get => _asyncCollectionHandler ?? throw new InvalidOperationException("The Handler was never set."); + private set => _asyncCollectionHandler = value; + } + + public static void RegisterHandlers() + { + ActionEventHandler = new ActionEventHandler(); + AsyncEventHandler = new AsyncEventHandler(); + AsyncObjectHandler = new AsyncEventHandler(); + AsyncObjectsHandler = new AsyncEventHandler>(); + AsyncMembersHandler = new AsyncEventHandler>(); + AsyncCollectionHandler = new AsyncEventHandler(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Selector.cs b/source/RevitLookup/Core/Selector.cs deleted file mode 100644 index cc708dca2..000000000 --- a/source/RevitLookup/Core/Selector.cs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using Autodesk.Revit.DB.ExtensibleStorage; -using Autodesk.Revit.DB.ExternalService; -using Autodesk.Revit.UI.Selection; -using Autodesk.Windows; -using RevitLookup.Services.Enums; - -namespace RevitLookup.Core; - -public static class Selector -{ - public static IList Snoop(SnoopableType type) - { - return type switch - { - SnoopableType.View => SnoopView(), - SnoopableType.Document => SnoopDocument(), - SnoopableType.Application => SnoopApplication(), - SnoopableType.UiApplication => SnoopUiApplication(), - SnoopableType.Database => SnoopDatabase(), - SnoopableType.DependentElements => SnoopDependentElements(), - SnoopableType.Selection => SnoopSelection(), - SnoopableType.Face => SnoopFace(), - SnoopableType.Edge => SnoopEdge(), - SnoopableType.SubElement => SnoopSubElement(), - SnoopableType.Point => SnoopPoint(), - SnoopableType.LinkedElement => SnoopLinkedElement(), - SnoopableType.ComponentManager => SnoopComponentManager(), - SnoopableType.PerformanceAdviser => SnoopPerformanceAdviser(), - SnoopableType.UpdaterRegistry => SnoopUpdaterRegistry(), - SnoopableType.Services => SnoopServices(), - SnoopableType.Schemas => SnoopSchemas(), - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) - }; - } - - private static IList SnoopView() - { - return [new SnoopableObject(Context.ActiveView)]; - } - - private static IList SnoopDocument() - { - return [new SnoopableObject(Context.ActiveDocument)]; - } - - private static IList SnoopApplication() - { - return [new SnoopableObject(Context.Application)]; - } - - private static IList SnoopUiApplication() - { - return [new SnoopableObject(Context.UiApplication)]; - } - - private static IList SnoopEdge() - { - return [SelectObject(ObjectType.Edge)]; - } - - private static IList SnoopFace() - { - return [SelectObject(ObjectType.Face)]; - } - - private static IList SnoopSubElement() - { - return [SelectObject(ObjectType.Subelement)]; - } - - private static IList SnoopPoint() - { - return [SelectObject(ObjectType.PointOnElement)]; - } - - private static IList SnoopLinkedElement() - { - return [SelectObject(ObjectType.LinkedElement)]; - } - - private static IList SnoopSelection() - { - var selectedIds = Context.UiApplication.ActiveUIDocument.Selection.GetElementIds(); - if (selectedIds.Count > 0) - return Context.ActiveDocument - .GetElements(selectedIds) - .WherePasses(new ElementIdSetFilter(selectedIds)) - .Select(element => new SnoopableObject(element)) - .ToArray(); - - return Context.ActiveDocument - .GetElements(Context.ActiveView!.Id) - .Select(element => new SnoopableObject(element)) - .ToArray(); - } - - private static IList SnoopDatabase() - { - var elementTypes = Context.ActiveDocument.GetElements().WhereElementIsElementType(); - var elementInstances = Context.ActiveDocument.GetElements().WhereElementIsNotElementType(); - return elementTypes - .UnionWith(elementInstances) - .Select(element => new SnoopableObject(element)) - .ToArray(); - } - - private static IList SnoopDependentElements() - { - var selectedIds = Context.ActiveUiDocument!.Selection.GetElementIds(); - if (selectedIds.Count == 0) return Array.Empty(); - - var elements = new List(); - var selectedElements = Context.ActiveDocument.GetElements(selectedIds).WhereElementIsNotElementType(); - - foreach (var selectedElement in selectedElements) - { - var dependentElements = selectedElement.GetDependentElements(null); - foreach (var dependentElement in dependentElements) elements.Add(dependentElement); - } - - return Context.ActiveDocument.GetElements() - .WherePasses(new ElementIdSetFilter(elements)) - .Select(element => new SnoopableObject(element)) - .ToArray(); - } - - private static IList SnoopComponentManager() - { - return [new SnoopableObject(typeof(ComponentManager))]; - } - - private static IList SnoopPerformanceAdviser() - { - return [new SnoopableObject(PerformanceAdviser.GetPerformanceAdviser())]; - } - - private static IList SnoopUpdaterRegistry() - { - return UpdaterRegistry.GetRegisteredUpdaterInfos().Select(schema => new SnoopableObject(schema)).ToArray(); - } - - private static IList SnoopSchemas() - { - return Schema.ListSchemas().Select(schema => new SnoopableObject(schema)).ToArray(); - } - - private static IList SnoopServices() - { - return ExternalServiceRegistry.GetServices().Select(service => new SnoopableObject(service)).ToArray(); - } - - private static SnoopableObject SelectObject(ObjectType objectType) - { - var reference = Context.ActiveUiDocument!.Selection.PickObject(objectType); - - object element; - switch (objectType) - { - case ObjectType.Edge: - case ObjectType.Face: - element = Context.ActiveDocument.GetElement(reference).GetGeometryObjectFromReference(reference); - break; - case ObjectType.Element: - case ObjectType.Subelement: - element = Context.ActiveDocument.GetElement(reference); - break; - case ObjectType.PointOnElement: - element = reference.GlobalPoint; - break; - case ObjectType.LinkedElement: - var revitLinkInstance = reference.ElementId.ToElement(Context.ActiveDocument); - element = revitLinkInstance.GetLinkDocument().GetElement(reference.LinkedElementId); - break; - case ObjectType.Nothing: - default: - throw new NotSupportedException(); - } - - return new SnoopableObject(element); - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Tools/RevitSettings/RevitConfigurator.cs b/source/RevitLookup/Core/Tools/RevitSettings/RevitConfigurator.cs new file mode 100644 index 000000000..04accf683 --- /dev/null +++ b/source/RevitLookup/Core/Tools/RevitSettings/RevitConfigurator.cs @@ -0,0 +1,269 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Text; +using RevitLookup.Abstractions.ObservableModels.Entries; + +namespace RevitLookup.Core.Tools.RevitSettings; + +[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] +[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] +public sealed class RevitConfigurator +{ + private const string BackupSuffix = "_RevitLookupBackup_"; + private const int DefaultBufferSize = 4096; // System.IO.File source code + + private const char CommentChar = ';'; + private const string SessionOptionsCategory = "[Jrn.SessionOptions]"; + private const string RevitAttributeRecord = " Rvt.Attr."; + + private readonly Encoding _encoding; + private readonly SemaphoreSlim _asyncLock = new(1, 1); + private readonly string _userIniPath = Context.Application.CurrentUsersDataFolderPath.AppendPath("Revit.ini"); + + private readonly string _defaultIniPath = Environment + .GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + .AppendPath("Autodesk", $"RVT {Context.Application.VersionNumber}", "UserDataCache", "Revit.ini"); + + private bool _backupDone; + + public RevitConfigurator() + { +#if NETCOREAPP + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); +#endif + _encoding = Encoding.GetEncoding(1251); + } + + public async Task> ReadAsync() + { + return await Task.Run(() => + { + var journalConfigurations = ParseJournalSource(); + var userConfigurations = ParseIniFile(false); + var defaultConfigurations = ParseIniFile(true); + + return MergeSources(journalConfigurations, userConfigurations, defaultConfigurations); + }); + } + + private List ParseJournalSource() + { + var currentJournal = Context.Application.RecordingJournalFilename; + var journalsPath = Directory.GetParent(currentJournal)!; + var journals = Directory.EnumerateFiles(journalsPath.FullName, "journal*txt").Reverse(); + + foreach (var journal in journals) + { + if (journal == currentJournal) continue; + + var lines = File.ReadLines(journal, _encoding); + foreach (var sessionOptions in lines.Reverse()) + { + if (!sessionOptions.Contains(SessionOptionsCategory)) continue; + + var startIndex = sessionOptions.IndexOf(SessionOptionsCategory, StringComparison.Ordinal) + SessionOptionsCategory.Length; + var optionsPart = sessionOptions[startIndex..]; + + var parts = optionsPart.Split([RevitAttributeRecord], StringSplitOptions.RemoveEmptyEntries) + .Select(line => line.Trim()) + .ToArray(); + + var entries = new List(); + foreach (var part in parts) + { + var keyValue = part.Split([':'], 2); + var keyParts = keyValue[0].Split('.'); + + var section = keyParts[0]; + var entry = keyParts[1]; + var value = keyValue[1].Trim(); + + entries.Add(new ObservableIniEntry + { + Category = section, + Property = entry, + Value = value + }); + } + + return entries; + } + } + + return []; + } + + private List ParseIniFile(bool useDefault) + { + var path = useDefault ? _defaultIniPath : _userIniPath; + if (!File.Exists(path)) return []; + + var entries = new List(); + var lines = File.ReadLines(path, Encoding.Unicode); + var currentCategory = string.Empty; + + foreach (var line in lines) + { + var trimmedLine = line.Trim(); + if (string.IsNullOrWhiteSpace(trimmedLine)) continue; + + if (trimmedLine.StartsWith("[") && trimmedLine.EndsWith("]")) + { + currentCategory = trimmedLine.Trim('[', ']'); + continue; + } + + var isActive = !trimmedLine.StartsWith(CommentChar.ToString()); + if (!isActive) + { + trimmedLine = trimmedLine.TrimStart(CommentChar).Trim(); + } + + var keyValue = trimmedLine.Split(['='], 2); + if (keyValue.Length != 2) continue; + + var property = keyValue[0].Trim(); + var value = keyValue[1].Trim(); + + var entry = new ObservableIniEntry + { + Category = currentCategory, + Property = property, + Value = value + }; + + if (useDefault) + { + entry.DefaultValue = value; + } + else + { + entry.IsActive = isActive; + entry.UserDefined = true; + } + + entries.Add(entry); + } + + return entries; + } + + private List MergeSources( + List journalEntries, + List userEntries, + List defaultEntries) + { + foreach (var userEntry in userEntries) + { + var existingEntry = journalEntries.FirstOrDefault(entry => entry.Category == userEntry.Category && entry.Property == userEntry.Property); + if (existingEntry != null) + { + existingEntry.Value = userEntry.Value; + existingEntry.IsActive = userEntry.IsActive; + existingEntry.UserDefined = userEntry.UserDefined; + } + else + { + journalEntries.Add(userEntry); + } + } + + foreach (var defaultEntry in defaultEntries) + { + var existingEntry = journalEntries.FirstOrDefault(e => e.Category == defaultEntry.Category && e.Property == defaultEntry.Property); + if (existingEntry != null) + { + existingEntry.DefaultValue = defaultEntry.DefaultValue; + } + else + { + journalEntries.Add(defaultEntry); + } + } + + return journalEntries; + } + + + public async Task WriteAsync(List entries) + { + var lines = new List(); + + var sortedEntries = entries + .Where(entry => entry.UserDefined) + .OrderBy(entry => entry.Category) + .ThenBy(entry => entry.Property) + .GroupBy(entry => entry.Category) + .ToArray(); + + foreach (var entryGroup in sortedEntries) + { + lines.Add($"[{entryGroup.Key}]"); + foreach (var entry in entryGroup) + { + var lineBuilder = new StringBuilder(); + + if (!entry.IsActive) lineBuilder.Append(CommentChar); + lineBuilder.Append(entry.Property); + lineBuilder.Append("="); + lineBuilder.Append(entry.Value); + + lines.Add(lineBuilder.ToString()); + } + } + + try + { + await _asyncLock.WaitAsync(); + + var filePath = Path.GetDirectoryName(_userIniPath)!; + var fileName = Path.GetFileNameWithoutExtension(_userIniPath); + if (!_backupDone && File.Exists(_userIniPath)) + { + var backupFileName = $"{fileName}{BackupSuffix}{DateTime.Now.ToString("yyyyMMddHHmmss", DateTimeFormatInfo.InvariantInfo)}.ini"; + File.Copy(_userIniPath, Path.Combine(filePath, backupFileName)); + _backupDone = true; + } + +#if NETCOREAPP + await using var stream = new FileStream(_userIniPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous); + await using var writer = new StreamWriter(stream, Encoding.Unicode); +#else + using var stream = new FileStream(_userIniPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read, DefaultBufferSize, FileOptions.Asynchronous); + using var writer = new StreamWriter(stream, Encoding.Unicode); +#endif + foreach (var line in lines) + { + await writer.WriteLineAsync(line); + } + + stream.SetLength(stream.Position); + await writer.FlushAsync(); + } + finally + { + _asyncLock.Release(); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Tools/Search/ElementsFinder.cs b/source/RevitLookup/Core/Tools/Search/ElementsFinder.cs new file mode 100644 index 000000000..8d61793fa --- /dev/null +++ b/source/RevitLookup/Core/Tools/Search/ElementsFinder.cs @@ -0,0 +1,102 @@ +namespace RevitLookup.Core.Tools.Search; + +public static class ElementsFinder +{ + [Pure] + public static List SearchElements(string searchText) + { + var activeDocument = Context.ActiveDocument; + if (activeDocument is null) return []; + + var rows = searchText.Split([Environment.NewLine], StringSplitOptions.RemoveEmptyEntries); + var items = ParseRawRequest(rows); + var results = new List(items.Count); + + foreach (var rawId in items) + { +#if REVIT2024_OR_GREATER + if (long.TryParse(rawId, out var id)) + { + var element = activeDocument.GetElement(new ElementId(id)); +#else + if (int.TryParse(rawId, out var id)) + { + var element = activeDocument.GetElement(new ElementId(id)); +#endif + if (element is not null) results.Add(element); + } + else if (rawId.Length == 45 && rawId.Count(c => c == '-') == 5) + { + var element = activeDocument.GetElement(rawId); + if (element is not null) results.Add(element); + } + else if (rawId.Length == 22 && rawId.Count(c => c == ' ') == 0) + { + var elements = SearchByIfcGuid(rawId, activeDocument); + results.AddRange(elements); + } + else + { + var elements = SearchByName(rawId, activeDocument); + results.AddRange(elements); + } + } + + return results; + } + + private static List ParseRawRequest(string[] rows) + { + var items = new List(rows.Length); + var delimiters = new[] {'\t', ';', ',', ' '}; + foreach (var row in rows) + { + for (var i = 0; i < delimiters.Length; i++) + { + var delimiter = delimiters[i]; + var split = row.Split([delimiter], StringSplitOptions.RemoveEmptyEntries); + if (split.Length > 1 || i == delimiters.Length - 1 || split.Length == 1 && split[0] != row) + { + items.AddRange(split); + break; + } + } + } + + return items; + } + + private static IEnumerable SearchByName(string rawId, Document document) + { + var elementTypes = document.GetElements().WhereElementIsElementType(); + var elementInstances = document.GetElements().WhereElementIsNotElementType(); + return elementTypes + .UnionWith(elementInstances) + .Where(element => element.Name.Contains(rawId, StringComparison.OrdinalIgnoreCase)); + } + + private static IList SearchByIfcGuid(string rawId, Document document) + { + var guidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_GUID)); + var typeGuidProvider = new ParameterValueProvider(new ElementId(BuiltInParameter.IFC_TYPE_GUID)); +#if REVIT2022_OR_GREATER + var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId); + var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId); +#else + var filterRule = new FilterStringRule(guidProvider, new FilterStringEquals(), rawId, true); + var typeFilterRule = new FilterStringRule(typeGuidProvider, new FilterStringEquals(), rawId, true); +#endif + var elementFilter = new ElementParameterFilter(filterRule); + var typeElementFilter = new ElementParameterFilter(typeFilterRule); + + var typeGuidsCollector = document + .GetElements() + .WherePasses(typeElementFilter); + + return document + .GetElements() + .WherePasses(elementFilter) + .UnionWith(typeGuidsCollector) + .ToElements(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Tools/Units/UnitsCollector.cs b/source/RevitLookup/Core/Tools/Units/UnitsCollector.cs new file mode 100644 index 000000000..d34447b74 --- /dev/null +++ b/source/RevitLookup/Core/Tools/Units/UnitsCollector.cs @@ -0,0 +1,141 @@ +using System.Reflection; +using System.Text; +using RevitLookup.Abstractions.Models.Tools; + +namespace RevitLookup.Core.Tools.Units; + +public static class UnitsCollector +{ + public static List GetBuiltinParametersInfo() + { + var parameters = Enum.GetValues(typeof(BuiltInParameter)); + var result = new List(parameters.Length); + foreach (BuiltInParameter parameter in parameters) + try + { + result.Add(new UnitInfo + { + Unit = parameter.ToString(), + Label = parameter.ToLabel(), + Value = parameter + }); + } + catch + { + // ignored + // Some parameters don't have a label + } + + return result; + } + + public static List GetBuiltinCategoriesInfo() + { + var categories = Enum.GetValues(typeof(BuiltInCategory)); + var result = new List(categories.Length); + foreach (BuiltInCategory category in categories) + try + { + result.Add(new UnitInfo + { + Unit = category.ToString(), + Label = category.ToLabel(), + Value = category + }); + } + catch + { + // ignored + // Some categories don't have a label + } + + return result; + } + + public static List GetForgeInfo() + { + const BindingFlags searchFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly; + + var dataTypes = new List(); +#if REVIT2022_OR_GREATER + dataTypes.AddRange(typeof(UnitTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId.Boolean).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId.String).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId.Int).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId.Reference).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(ParameterTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(GroupTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(DisciplineTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SymbolTypeId).GetProperties(searchFlags)); +#else + dataTypes.AddRange(typeof(UnitTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SpecTypeId).GetProperties(searchFlags)); + dataTypes.AddRange(typeof(SymbolTypeId).GetProperties(searchFlags)); +#endif + return dataTypes.Select(info => + { + var typeId = (ForgeTypeId) info.GetValue(null)!; + return new UnitInfo + { + Unit = typeId.TypeId, + Label = GetLabel(typeId, info), + Class = GetClassName(info), + Value = typeId + }; + }) + .ToList(); + } + + + private static string GetClassName(PropertyInfo property) + { + var type = property.DeclaringType!; + var stringBuilder = new StringBuilder(); + stringBuilder.Append(type.Name); + stringBuilder.Append('.'); + stringBuilder.Append(property.Name); + + while (type.IsNested) + { + type = type.DeclaringType!; + stringBuilder.Insert(0, '.'); + stringBuilder.Insert(0, type.Name); + } + + return stringBuilder.ToString(); + } + + private static string GetLabel(ForgeTypeId typeId, PropertyInfo property) + { + if (typeId.Empty()) return string.Empty; + if (property.Name == nameof(SpecTypeId.Custom)) return string.Empty; + + var type = property.DeclaringType; + while (type!.IsNested) + { + type = type.DeclaringType; + } + + try + { + return type.Name switch + { + nameof(UnitTypeId) => typeId.ToUnitLabel(), + nameof(SpecTypeId) => typeId.ToSpecLabel(), + nameof(SymbolTypeId) => typeId.ToSymbolLabel(), +#if REVIT2022_OR_GREATER + nameof(ParameterTypeId) => typeId.ToParameterLabel(), + nameof(GroupTypeId) => typeId.ToGroupLabel(), + nameof(DisciplineTypeId) => typeId.ToDisciplineLabel(), +#endif + _ => throw new ArgumentOutOfRangeException(nameof(typeId), typeId, "Unknown Forge Type Identifier") + }; + } + catch + { + //Some parameter label thrown an exception + return string.Empty; + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Utils/DescriptorUtils.cs b/source/RevitLookup/Core/Utils/DescriptorUtils.cs deleted file mode 100644 index 24c1cbdbd..000000000 --- a/source/RevitLookup/Core/Utils/DescriptorUtils.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -using RevitLookup.Core.ComponentModel; -using RevitLookup.Core.ComponentModel.Descriptors; - -namespace RevitLookup.Core.Utils; - -public static class DescriptorUtils -{ - [NotNull] - public static Descriptor FindSuitableDescriptor(Type type) - { - var descriptor = new ObjectDescriptor(); - - if (type is null) - { - descriptor.Type = nameof(Object); - descriptor.TypeFullName = "System.Object"; - } - else - { - ValidateProperties(descriptor, type); - } - - return descriptor; - } - - [NotNull] - public static Descriptor FindSuitableDescriptor(object obj) - { - var descriptor = DescriptorMap.FindDescriptor(obj, null); - - if (obj is null) - { - descriptor.Type = nameof(Object); - descriptor.TypeFullName = "System.Object"; - } - else - { - var type = obj.GetType(); - ValidateProperties(descriptor, type); - } - - return descriptor; - } - - [CanBeNull] - public static Descriptor FindSuitableDescriptor(object obj, Type type) - { - var descriptor = DescriptorMap.FindDescriptor(obj, type); - if (descriptor is null) return null; - - ValidateProperties(descriptor, type); - return descriptor; - } - - public static string MakeGenericFullTypeName(Type type) - { - if (type.IsGenericType) return type.FullName![..type.FullName!.IndexOf('[')]; - return type.FullName; - } - - public static string MakeGenericTypeName(Type type) - { - if (!type.IsGenericType) return type.Name; - - var typeName = type.Name; - var apostropheIndex = typeName.IndexOf('`'); - if (apostropheIndex > 0) typeName = typeName.Substring(0, apostropheIndex); - typeName += "<"; - var genericArguments = type.GetGenericArguments(); - for (var i = 0; i < genericArguments.Length; i++) - { - typeName += MakeGenericTypeName(genericArguments[i]); - if (i < genericArguments.Length - 1) typeName += ", "; - } - - typeName += ">"; - return typeName; - } - - private static void ValidateProperties(Descriptor descriptor, Type type) - { - descriptor.Type = MakeGenericTypeName(type); - descriptor.Name ??= descriptor.Type; - descriptor.TypeFullName = MakeGenericFullTypeName(type); - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Utils/SnoopUtils.cs b/source/RevitLookup/Core/Utils/SnoopUtils.cs deleted file mode 100644 index 85e0c73d2..000000000 --- a/source/RevitLookup/Core/Utils/SnoopUtils.cs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2003-2024 by Autodesk, Inc. -// -// Permission to use, copy, modify, and distribute this software in -// object code form for any purpose and without fee is hereby granted, -// provided that the above copyright notice appears in all copies and -// that both that copyright notice and the limited warranty and -// restricted rights notice below appear in all supporting -// documentation. -// -// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. -// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF -// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. -// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE -// UNINTERRUPTED OR ERROR FREE. -// -// Use, duplication, or disclosure by the U.S. Government is subject to -// restrictions set forth in FAR 52.227-19 (Commercial Computer -// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) -// (Rights in Technical Data and Computer Software), as applicable. - -namespace RevitLookup.Core.Utils; - -public static class SnoopUtils -{ - public static IList ParseEnumerable(this IDescriptorEnumerator descriptor, SnoopableObject snoopableObject) - { - var items = new List(); - descriptor.Enumerator.Reset(); - - while (descriptor.Enumerator.MoveNext()) - { - var item = new SnoopableObject(descriptor.Enumerator, snoopableObject.Context); - Redirect(item); - items.Add(item); - } - - if (descriptor.Enumerator is IDisposable disposable) - { - disposable.Dispose(); - } - - return items; - } - - public static void Redirect(string target, SnoopableObject snoopableObject) - { - while (snoopableObject.Descriptor is IDescriptorRedirection redirection) - { - if (!redirection.TryRedirect(snoopableObject.Context, target, out var output)) break; - - var descriptor = DescriptorUtils.FindSuitableDescriptor(output); - descriptor.Description ??= snoopableObject.Descriptor.Description; - snoopableObject.Descriptor = descriptor; - snoopableObject.Object = output; - } - } - - public static void Redirect(SnoopableObject snoopableObject) - { - Redirect(null, snoopableObject); - } -} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/BoundingBoxVisualizationServer.cs b/source/RevitLookup/Core/Visualization/BoundingBoxVisualizationServer.cs new file mode 100644 index 000000000..8b0e51964 --- /dev/null +++ b/source/RevitLookup/Core/Visualization/BoundingBoxVisualizationServer.cs @@ -0,0 +1,313 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class BoundingBoxVisualizationServer : IDirectContext3DServer +{ + private BoundingBoxXYZ _box = null!; //Cant be null after registration + private bool _hasGeometryUpdates = true; + private bool _hasEffectsUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + private readonly RenderingBufferStorage _surfaceBuffer = new(); + private readonly RenderingBufferStorage _edgeBuffer = new(); + + private readonly RenderingBufferStorage[] _axisBuffers = Enumerable.Range(0, 6) + .Select(_ => new RenderingBufferStorage()) + .ToArray(); + + private readonly XYZ[] _normals = + [ + XYZ.BasisX, + XYZ.BasisY, + XYZ.BasisZ + ]; + + private double _transparency; + + private bool _drawSurface; + private bool _drawEdge; + private bool _drawAxis; + + private Color _surfaceColor = Color.InvalidColorValue; + private Color _edgeColor = Color.InvalidColorValue; + private Color _axisColor = Color.InvalidColorValue; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "BoundingBoxXYZ visualization server"; + public string GetDescription() => "BoundingBoxXYZ geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawSurface && _transparency > 0; + + public Outline GetBoundingBox(View view) + { + return new Outline(_box.Min, _box.Max); + } + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates || !_surfaceBuffer.IsValid() || !_edgeBuffer.IsValid()) + { + MapGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawSurface) + { + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + DrawContext.FlushBuffer(_surfaceBuffer.VertexBuffer, + _surfaceBuffer.VertexBufferCount, + _surfaceBuffer.IndexBuffer, + _surfaceBuffer.IndexBufferCount, + _surfaceBuffer.VertexFormat, + _surfaceBuffer.EffectInstance, PrimitiveType.TriangleList, 0, + _surfaceBuffer.PrimitiveCount); + } + } + + if (_drawEdge) + { + DrawContext.FlushBuffer(_edgeBuffer.VertexBuffer, + _edgeBuffer.VertexBufferCount, + _edgeBuffer.IndexBuffer, + _edgeBuffer.IndexBufferCount, + _edgeBuffer.VertexFormat, + _edgeBuffer.EffectInstance, PrimitiveType.LineList, 0, + _edgeBuffer.PrimitiveCount); + } + + if (_drawAxis) + { + foreach (var buffer in _axisBuffers) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.LineList, 0, + buffer.PrimitiveCount); + } + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void MapGeometryBuffer() + { + RenderHelper.MapBoundingBoxSurfaceBuffer(_surfaceBuffer, _box); + RenderHelper.MapBoundingBoxEdgeBuffer(_edgeBuffer, _box); + MapAxisBuffers(); + } + + private void MapAxisBuffers() + { + var unitVector = new XYZ(1, 1, 1); + var minPoint = _box.Transform.OfPoint(_box.Min); + var maxPoint = _box.Transform.OfPoint(_box.Max); + var axisLength = RenderGeometryHelper.InterpolateAxisLengthByPoints(minPoint, maxPoint); + + for (var i = 0; i < _normals.Length; i++) + { + var normal = _normals[i]; + var minBuffer = _axisBuffers[i]; + var maxBuffer = _axisBuffers[i + _normals.Length]; + + RenderHelper.MapNormalVectorBuffer(minBuffer, minPoint - unitVector * Context.Application.ShortCurveTolerance, normal, axisLength); + RenderHelper.MapNormalVectorBuffer(maxBuffer, maxPoint + unitVector * Context.Application.ShortCurveTolerance, -normal, axisLength); + } + } + + private void UpdateEffects() + { + _surfaceBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + _surfaceBuffer.EffectInstance.SetColor(_surfaceColor); + _surfaceBuffer.EffectInstance.SetTransparency(_transparency); + + _edgeBuffer.EffectInstance ??= new EffectInstance(_edgeBuffer.FormatBits); + _edgeBuffer.EffectInstance.SetColor(_edgeColor); + + foreach (var buffer in _axisBuffers) + { + buffer.EffectInstance ??= new EffectInstance(_edgeBuffer.FormatBits); + buffer.EffectInstance.SetColor(_axisColor); + } + } + + public void UpdateSurfaceColor(Color color) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _surfaceColor = color; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateEdgeColor(Color color) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _edgeColor = color; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateAxisColor(Color color) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _axisColor = color; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + + public void UpdateSurfaceVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawSurface = visible; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateEdgeVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawEdge = visible; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateAxisVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawAxis = visible; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(BoundingBoxXYZ box) + { + _box = box; + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/Buffers/RenderingBufferStorage.cs b/source/RevitLookup/Core/Visualization/Buffers/RenderingBufferStorage.cs new file mode 100644 index 000000000..1e9673311 --- /dev/null +++ b/source/RevitLookup/Core/Visualization/Buffers/RenderingBufferStorage.cs @@ -0,0 +1,25 @@ +using Autodesk.Revit.DB.DirectContext3D; + +namespace RevitLookup.Core.Visualization.Buffers; + +public sealed class RenderingBufferStorage +{ + public VertexFormatBits FormatBits { get; set; } + public int PrimitiveCount { get; set; } + public int VertexBufferCount { get; set; } + public int IndexBufferCount { get; set; } + public VertexBuffer? VertexBuffer { get; set; } + public IndexBuffer? IndexBuffer { get; set; } + public VertexFormat? VertexFormat { get; set; } + public EffectInstance? EffectInstance { get; set; } + + public bool IsValid() + { + if (VertexBuffer is null || !VertexBuffer.IsValid()) return false; + if (IndexBuffer is null || !IndexBuffer.IsValid()) return false; + if (VertexFormat is null || !VertexFormat.IsValid()) return false; + if (EffectInstance is null || !EffectInstance.IsValid()) return false; + + return true; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Models/SearchResults.cs b/source/RevitLookup/Core/Visualization/Events/RenderFailedEventArgs.cs similarity index 85% rename from source/RevitLookup/Models/SearchResults.cs rename to source/RevitLookup/Core/Visualization/Events/RenderFailedEventArgs.cs index c62eb9dc1..b78950072 100644 --- a/source/RevitLookup/Models/SearchResults.cs +++ b/source/RevitLookup/Core/Visualization/Events/RenderFailedEventArgs.cs @@ -18,10 +18,9 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. -namespace RevitLookup.Models; +namespace RevitLookup.Core.Visualization.Events; -public sealed class SearchResults +public sealed class RenderFailedEventArgs { - public IList Data { get; init; } - public IList Objects { get; init; } + public required Exception ExceptionObject { get; set; } } \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/FaceVisualizationServer.cs b/source/RevitLookup/Core/Visualization/FaceVisualizationServer.cs new file mode 100644 index 000000000..64389fb14 --- /dev/null +++ b/source/RevitLookup/Core/Visualization/FaceVisualizationServer.cs @@ -0,0 +1,305 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class FaceVisualizationServer : IDirectContext3DServer +{ + private Face _face = null!; //Cant be null after registration + private bool _hasEffectsUpdates = true; + private bool _hasGeometryUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + private readonly RenderingBufferStorage _meshGridBuffer = new(); + private readonly RenderingBufferStorage _normalBuffer = new(); + private readonly RenderingBufferStorage _surfaceBuffer = new(); + + private double _extrusion; + private double _transparency; + + private Color _meshColor = Color.InvalidColorValue; + private Color _normalColor = Color.InvalidColorValue; + private Color _surfaceColor = Color.InvalidColorValue; + + private bool _drawMeshGrid; + private bool _drawNormalVector; + private bool _drawSurface; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "Face visualization server"; + public string GetDescription() => "Face geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawSurface && _transparency > 0; + + public Outline? GetBoundingBox(View view) + { + if (_face.Reference is null) return null; + + var element = _face.Reference.ElementId.ToElement(view.Document)!; + var boundingBox = element.get_BoundingBox(null) ?? element.get_BoundingBox(view); + if (boundingBox is null) return null; + + var minPoint = boundingBox.Transform.OfPoint(boundingBox.Min); + var maxPoint = boundingBox.Transform.OfPoint(boundingBox.Max); + + return new Outline(minPoint, maxPoint); + } + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates || !_surfaceBuffer.IsValid() || !_meshGridBuffer.IsValid() || !_normalBuffer.IsValid()) + { + MapGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawSurface) + { + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + DrawContext.FlushBuffer(_surfaceBuffer.VertexBuffer, + _surfaceBuffer.VertexBufferCount, + _surfaceBuffer.IndexBuffer, + _surfaceBuffer.IndexBufferCount, + _surfaceBuffer.VertexFormat, + _surfaceBuffer.EffectInstance, PrimitiveType.TriangleList, 0, + _surfaceBuffer.PrimitiveCount); + } + } + + if (_drawMeshGrid) + { + DrawContext.FlushBuffer(_meshGridBuffer.VertexBuffer, + _meshGridBuffer.VertexBufferCount, + _meshGridBuffer.IndexBuffer, + _meshGridBuffer.IndexBufferCount, + _meshGridBuffer.VertexFormat, + _meshGridBuffer.EffectInstance, PrimitiveType.LineList, 0, + _meshGridBuffer.PrimitiveCount); + } + + if (_drawNormalVector) + { + DrawContext.FlushBuffer(_normalBuffer.VertexBuffer, + _normalBuffer.VertexBufferCount, + _normalBuffer.IndexBuffer, + _normalBuffer.IndexBufferCount, + _normalBuffer.VertexFormat, + _normalBuffer.EffectInstance, PrimitiveType.LineList, 0, + _normalBuffer.PrimitiveCount); + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void MapGeometryBuffer() + { + var mesh = _face.Triangulate(); + var faceBox = _face.GetBoundingBox(); + var center = (faceBox.Min + faceBox.Max) / 2; + var normal = _face.ComputeNormal(center); + var offset = RenderGeometryHelper.InterpolateOffsetByArea(_face.Area); + var normalLength = RenderGeometryHelper.InterpolateAxisLengthByArea(_face.Area); + + RenderHelper.MapSurfaceBuffer(_surfaceBuffer, mesh, _extrusion); + RenderHelper.MapMeshGridBuffer(_meshGridBuffer, mesh, _extrusion); + RenderHelper.MapNormalVectorBuffer(_normalBuffer, _face.Evaluate(center) + normal * (offset + _extrusion), normal, normalLength); + } + + private void UpdateEffects() + { + _surfaceBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + _meshGridBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + _normalBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + + _surfaceBuffer.EffectInstance.SetColor(_surfaceColor); + _meshGridBuffer.EffectInstance.SetColor(_meshColor); + _normalBuffer.EffectInstance.SetColor(_normalColor); + _surfaceBuffer.EffectInstance.SetTransparency(_transparency); + } + + public void UpdateSurfaceColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _surfaceColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateMeshGridColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _meshColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateNormalVectorColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _normalColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateExtrusion(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _extrusion = value; + _hasGeometryUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateSurfaceVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawSurface = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateMeshGridVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawMeshGrid = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateNormalVectorVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawNormalVector = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(Face face) + { + _face = face; + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Modules/Visualization/Helpers/RenderGeometryHelper.cs b/source/RevitLookup/Core/Visualization/Helpers/RenderGeometryHelper.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/Helpers/RenderGeometryHelper.cs rename to source/RevitLookup/Core/Visualization/Helpers/RenderGeometryHelper.cs diff --git a/source/RevitLookup/Core/Visualization/Helpers/RenderHelper.cs b/source/RevitLookup/Core/Visualization/Helpers/RenderHelper.cs new file mode 100644 index 000000000..cdfe19aab --- /dev/null +++ b/source/RevitLookup/Core/Visualization/Helpers/RenderHelper.cs @@ -0,0 +1,514 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using RevitLookup.Core.Visualization.Buffers; + +namespace RevitLookup.Core.Visualization.Helpers; + +public static class RenderHelper +{ + public static void MapSurfaceBuffer(RenderingBufferStorage buffer, Mesh mesh, double offset) + { + var vertexCount = mesh.Vertices.Count; + var triangleCount = mesh.NumTriangles; + + buffer.VertexBufferCount = vertexCount; + buffer.PrimitiveCount = triangleCount; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + var normals = new List(mesh.NumberOfNormals); + + for (var i = 0; i < mesh.Vertices.Count; i++) + { + var normal = RenderGeometryHelper.GetMeshVertexNormal(mesh, i, mesh.DistributionOfNormals); + normals.Add(normal); + } + + for (var i = 0; i < mesh.Vertices.Count; i++) + { + var vertex = mesh.Vertices[i]; + var normal = normals[i]; + var offsetVertex = vertex + normal * offset; + var vertexPosition = new VertexPosition(offsetVertex); + vertexStream.AddVertex(vertexPosition); + } + + buffer.VertexBuffer.Unmap(); + buffer.IndexBufferCount = triangleCount * IndexTriangle.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamTriangle(); + + for (var i = 0; i < triangleCount; i++) + { + var meshTriangle = mesh.get_Triangle(i); + var index0 = (int) meshTriangle.get_Index(0); + var index1 = (int) meshTriangle.get_Index(1); + var index2 = (int) meshTriangle.get_Index(2); + indexStream.AddTriangle(new IndexTriangle(index0, index1, index2)); + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapCurveBuffer(RenderingBufferStorage buffer, IList vertices) + { + var vertexCount = vertices.Count; + + buffer.VertexBufferCount = vertexCount; + buffer.PrimitiveCount = vertexCount - 1; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + + foreach (var vertex in vertices) + { + var vertexPosition = new VertexPosition(vertex); + vertexStream.AddVertex(vertexPosition); + } + + buffer.VertexBuffer.Unmap(); + buffer.IndexBufferCount = (vertexCount - 1) * IndexLine.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamLine(); + + for (var i = 0; i < vertexCount - 1; i++) + { + indexStream.AddLine(new IndexLine(i, i + 1)); + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapCurveBuffer(RenderingBufferStorage buffer, IList vertices, double diameter) + { + var tubeSegments = RenderGeometryHelper.GetSegmentationTube(vertices, diameter); + var segmentVerticesCount = tubeSegments[0].Count; + var newVertexCount = vertices.Count * segmentVerticesCount; + + buffer.VertexBufferCount = newVertexCount; + buffer.PrimitiveCount = (vertices.Count - 1) * segmentVerticesCount * 4; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + + foreach (var segment in tubeSegments) + { + foreach (var point in segment) + { + var vertexPosition = new VertexPosition(point); + vertexStream.AddVertex(vertexPosition); + } + } + + buffer.VertexBuffer.Unmap(); + + buffer.IndexBufferCount = (vertices.Count - 1) * segmentVerticesCount * 4 * IndexLine.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamLine(); + + for (var i = 0; i < vertices.Count - 1; i++) + { + for (var j = 0; j < segmentVerticesCount; j++) + { + var currentStart = i * segmentVerticesCount + j; + var nextStart = (i + 1) * segmentVerticesCount + j; + var currentEnd = i * segmentVerticesCount + (j + 1) % segmentVerticesCount; + var nextEnd = (i + 1) * segmentVerticesCount + (j + 1) % segmentVerticesCount; + + // First triangle + indexStream.AddLine(new IndexLine(currentStart, nextStart)); + indexStream.AddLine(new IndexLine(nextStart, nextEnd)); + + // Second triangle + indexStream.AddLine(new IndexLine(nextEnd, currentEnd)); + indexStream.AddLine(new IndexLine(currentEnd, currentStart)); + } + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapCurveSurfaceBuffer(RenderingBufferStorage buffer, IList vertices, double diameter) + { + var tubeSegments = RenderGeometryHelper.GetSegmentationTube(vertices, diameter); + var segmentVerticesCount = tubeSegments[0].Count; + var newVertexCount = vertices.Count * segmentVerticesCount; + + buffer.VertexBufferCount = newVertexCount; + buffer.PrimitiveCount = (vertices.Count - 1) * segmentVerticesCount * 2; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + + foreach (var segment in tubeSegments) + { + foreach (var point in segment) + { + var vertexPosition = new VertexPosition(point); + vertexStream.AddVertex(vertexPosition); + } + } + + buffer.VertexBuffer.Unmap(); + + buffer.IndexBufferCount = (vertices.Count - 1) * segmentVerticesCount * 6 * IndexTriangle.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamTriangle(); + + for (var i = 0; i < vertices.Count - 1; i++) + { + for (var j = 0; j < segmentVerticesCount; j++) + { + var currentStart = i * segmentVerticesCount + j; + var nextStart = (i + 1) * segmentVerticesCount + j; + var currentEnd = i * segmentVerticesCount + (j + 1) % segmentVerticesCount; + var nextEnd = (i + 1) * segmentVerticesCount + (j + 1) % segmentVerticesCount; + + // First triangle + indexStream.AddTriangle(new IndexTriangle(currentStart, nextStart, nextEnd)); + + // Second triangle + indexStream.AddTriangle(new IndexTriangle(nextEnd, currentEnd, currentStart)); + } + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapMeshGridBuffer(RenderingBufferStorage buffer, Mesh mesh, double offset) + { + var vertexCount = mesh.Vertices.Count; + var triangleCount = mesh.NumTriangles; + + buffer.VertexBufferCount = vertexCount * 2; + buffer.PrimitiveCount = 3 * triangleCount * 2 + mesh.Vertices.Count; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + var normals = new List(mesh.NumberOfNormals); + + for (var i = 0; i < mesh.Vertices.Count; i++) + { + var normal = RenderGeometryHelper.GetMeshVertexNormal(mesh, i, mesh.DistributionOfNormals); + normals.Add(normal); + } + + foreach (var vertex in mesh.Vertices) + { + var vertexPosition = new VertexPosition(vertex); + vertexStream.AddVertex(vertexPosition); + } + + for (var i = 0; i < mesh.Vertices.Count; i++) + { + var vertex = mesh.Vertices[i]; + var normal = normals[i]; + var offsetVertex = vertex + normal * offset; + var vertexPosition = new VertexPosition(offsetVertex); + vertexStream.AddVertex(vertexPosition); + } + + buffer.VertexBuffer.Unmap(); + buffer.IndexBufferCount = (3 * triangleCount * 2 + mesh.Vertices.Count) * IndexLine.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamLine(); + + for (var i = 0; i < triangleCount; i++) + { + var meshTriangle = mesh.get_Triangle(i); + var index0 = (int) meshTriangle.get_Index(0); + var index1 = (int) meshTriangle.get_Index(1); + var index2 = (int) meshTriangle.get_Index(2); + + indexStream.AddLine(new IndexLine(index0, index1)); + indexStream.AddLine(new IndexLine(index1, index2)); + indexStream.AddLine(new IndexLine(index2, index0)); + } + + for (var i = 0; i < triangleCount; i++) + { + var meshTriangle = mesh.get_Triangle(i); + var index0 = (int) meshTriangle.get_Index(0) + vertexCount; + var index1 = (int) meshTriangle.get_Index(1) + vertexCount; + var index2 = (int) meshTriangle.get_Index(2) + vertexCount; + + indexStream.AddLine(new IndexLine(index0, index1)); + indexStream.AddLine(new IndexLine(index1, index2)); + indexStream.AddLine(new IndexLine(index2, index0)); + } + + for (var i = 0; i < mesh.Vertices.Count; i++) + { + indexStream.AddLine(new IndexLine(i, i + mesh.Vertices.Count)); + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapSideBuffer(RenderingBufferStorage buffer, XYZ min, XYZ max) + { + var vertexCount = 4; + var normal = (max - min).Normalize(); + var length = (max - min).GetLength() / 2; + + XYZ point1; + XYZ point2; + XYZ point3; + XYZ point4; + if (normal.IsAlmostEqualTo(XYZ.BasisX)) + { + point1 = new XYZ(min.X, min.Y - length, min.Z); + point2 = new XYZ(min.X, min.Y + length, min.Z); + point3 = new XYZ(max.X, max.Y - length, max.Z); + point4 = new XYZ(max.X, max.Y + length, max.Z); + } + else if (normal.IsAlmostEqualTo(XYZ.BasisY)) + { + point1 = new XYZ(min.X, min.Y, min.Z - length); + point2 = new XYZ(min.X, min.Y, min.Z + length); + point3 = new XYZ(max.X, max.Y, max.Z - length); + point4 = new XYZ(max.X, max.Y, max.Z + length); + } + else + { + point1 = new XYZ(min.X - length, min.Y, min.Z); + point2 = new XYZ(min.X + length, min.Y, min.Z); + point3 = new XYZ(max.X - length, max.Y, max.Z); + point4 = new XYZ(max.X + length, max.Y, max.Z); + } + + buffer.VertexBufferCount = vertexCount; + buffer.PrimitiveCount = 2; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + vertexStream.AddVertex(new VertexPosition(point1)); + vertexStream.AddVertex(new VertexPosition(point2)); + vertexStream.AddVertex(new VertexPosition(point3)); + vertexStream.AddVertex(new VertexPosition(point4)); + + buffer.VertexBuffer.Unmap(); + buffer.IndexBufferCount = 2 * IndexTriangle.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamTriangle(); + indexStream.AddTriangle(new IndexTriangle(0, 1, 2)); + indexStream.AddTriangle(new IndexTriangle(1, 2, 3)); + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapBoundingBoxSurfaceBuffer(RenderingBufferStorage buffer, BoundingBoxXYZ box) + { + var minPoint = box.Transform.OfPoint(box.Min); + var maxPoint = box.Transform.OfPoint(box.Max); + + XYZ[] corners = + [ + new(minPoint.X, minPoint.Y, minPoint.Z), + new(maxPoint.X, minPoint.Y, minPoint.Z), + new(maxPoint.X, maxPoint.Y, minPoint.Z), + new(minPoint.X, maxPoint.Y, minPoint.Z), + new(minPoint.X, minPoint.Y, maxPoint.Z), + new(maxPoint.X, minPoint.Y, maxPoint.Z), + new(maxPoint.X, maxPoint.Y, maxPoint.Z), + new(minPoint.X, maxPoint.Y, maxPoint.Z) + ]; + + int[] triangles = + [ + 0, 1, 2, 2, 3, 0, // bottom face + 4, 5, 6, 6, 7, 4, // top face + 0, 4, 5, 5, 1, 0, // front face + 1, 5, 6, 6, 2, 1, // right face + 2, 6, 7, 7, 3, 2, // back face + 3, 7, 4, 4, 0, 3 // left face + ]; + + buffer.VertexBufferCount = corners.Length; + buffer.PrimitiveCount = triangles.Length / 3; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + + foreach (var corner in corners) + { + var vertexPosition = new VertexPosition(corner); + vertexStream.AddVertex(vertexPosition); + } + + buffer.VertexBuffer.Unmap(); + + buffer.IndexBufferCount = triangles.Length * IndexTriangle.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamTriangle(); + + for (var i = 0; i < triangles.Length; i += 3) + { + indexStream.AddTriangle(new IndexTriangle(triangles[i], triangles[i + 1], triangles[i + 2])); + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapBoundingBoxEdgeBuffer(RenderingBufferStorage buffer, BoundingBoxXYZ box) + { + var minPoint = box.Transform.OfPoint(box.Min); + var maxPoint = box.Transform.OfPoint(box.Max); + + XYZ[] corners = + [ + new(minPoint.X, minPoint.Y, minPoint.Z), + new(maxPoint.X, minPoint.Y, minPoint.Z), + new(maxPoint.X, maxPoint.Y, minPoint.Z), + new(minPoint.X, maxPoint.Y, minPoint.Z), + new(minPoint.X, minPoint.Y, maxPoint.Z), + new(maxPoint.X, minPoint.Y, maxPoint.Z), + new(maxPoint.X, maxPoint.Y, maxPoint.Z), + new(minPoint.X, maxPoint.Y, maxPoint.Z) + ]; + + int[] edges = + [ + 0, 1, 1, 2, 2, 3, 3, 0, // bottom face + 4, 5, 5, 6, 6, 7, 7, 4, // top face + 0, 4, 1, 5, 2, 6, 3, 7 // vertical edges + ]; + + buffer.VertexBufferCount = corners.Length; + buffer.PrimitiveCount = edges.Length / 2; + + var vertexBufferSizeInFloats = VertexPosition.GetSizeInFloats() * buffer.VertexBufferCount; + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + + foreach (var corner in corners) + { + var vertexPosition = new VertexPosition(corner); + vertexStream.AddVertex(vertexPosition); + } + + buffer.VertexBuffer.Unmap(); + + buffer.IndexBufferCount = edges.Length * IndexLine.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamLine(); + + for (var i = 0; i < edges.Length; i += 2) + { + indexStream.AddLine(new IndexLine(edges[i], edges[i + 1])); + } + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } + + public static void MapNormalVectorBuffer(RenderingBufferStorage buffer, XYZ origin, XYZ vector, double length) + { + var headSize = length > 1 ? 0.2 : length * 0.2; + + var endPoint = origin + vector * length; + var arrowHeadBase = endPoint - vector * headSize; + var basisVector = Math.Abs(vector.Z).IsAlmostEqual(1) ? XYZ.BasisY : XYZ.BasisZ; + var perpendicular1 = vector.CrossProduct(basisVector).Normalize().Multiply(headSize * 0.5); + + buffer.VertexBufferCount = 4; + buffer.PrimitiveCount = 3; + + var vertexBufferSizeInFloats = 4 * VertexPosition.GetSizeInFloats(); + buffer.FormatBits = VertexFormatBits.Position; + buffer.VertexBuffer = new VertexBuffer(vertexBufferSizeInFloats); + buffer.VertexBuffer.Map(vertexBufferSizeInFloats); + + var vertexStream = buffer.VertexBuffer.GetVertexStreamPosition(); + vertexStream.AddVertex(new VertexPosition(origin)); + vertexStream.AddVertex(new VertexPosition(endPoint)); + vertexStream.AddVertex(new VertexPosition(arrowHeadBase + perpendicular1)); + vertexStream.AddVertex(new VertexPosition(arrowHeadBase - perpendicular1)); + + buffer.VertexBuffer.Unmap(); + buffer.IndexBufferCount = 3 * IndexLine.GetSizeInShortInts(); + buffer.IndexBuffer = new IndexBuffer(buffer.IndexBufferCount); + buffer.IndexBuffer.Map(buffer.IndexBufferCount); + + var indexStream = buffer.IndexBuffer.GetIndexStreamLine(); + indexStream.AddLine(new IndexLine(0, 1)); + indexStream.AddLine(new IndexLine(1, 2)); + indexStream.AddLine(new IndexLine(1, 3)); + + buffer.IndexBuffer.Unmap(); + buffer.VertexFormat = new VertexFormat(buffer.FormatBits); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/MeshVisualizationServer.cs b/source/RevitLookup/Core/Visualization/MeshVisualizationServer.cs new file mode 100644 index 000000000..c4b472e9c --- /dev/null +++ b/source/RevitLookup/Core/Visualization/MeshVisualizationServer.cs @@ -0,0 +1,313 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class MeshVisualizationServer : IDirectContext3DServer +{ + private Mesh _mesh = null!; //Cant be null after registration + private bool _hasEffectsUpdates = true; + private bool _hasGeometryUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + + private RenderingBufferStorage[] _normalBuffers = []; + private readonly RenderingBufferStorage _surfaceBuffer = new(); + private readonly RenderingBufferStorage _meshGridBuffer = new(); + + private double _extrusion; + private double _transparency; + + private bool _drawMeshGrid; + private bool _drawNormalVector; + private bool _drawSurface; + + private Color _meshColor = Color.InvalidColorValue; + private Color _normalColor = Color.InvalidColorValue; + private Color _surfaceColor = Color.InvalidColorValue; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "Mesh visualization server"; + public string GetDescription() => "Mesh geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawSurface && _transparency > 0; + public Outline? GetBoundingBox(View view) => null; + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates || !_surfaceBuffer.IsValid() || !_meshGridBuffer.IsValid()) + { + MapGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawSurface) + { + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + DrawContext.FlushBuffer(_surfaceBuffer.VertexBuffer, + _surfaceBuffer.VertexBufferCount, + _surfaceBuffer.IndexBuffer, + _surfaceBuffer.IndexBufferCount, + _surfaceBuffer.VertexFormat, + _surfaceBuffer.EffectInstance, PrimitiveType.TriangleList, 0, + _surfaceBuffer.PrimitiveCount); + } + } + + if (_drawMeshGrid) + { + DrawContext.FlushBuffer(_meshGridBuffer.VertexBuffer, + _meshGridBuffer.VertexBufferCount, + _meshGridBuffer.IndexBuffer, + _meshGridBuffer.IndexBufferCount, + _meshGridBuffer.VertexFormat, + _meshGridBuffer.EffectInstance, PrimitiveType.LineList, 0, + _meshGridBuffer.PrimitiveCount); + } + + if (_drawNormalVector) + { + foreach (var buffer in _normalBuffers) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.LineList, 0, + buffer.PrimitiveCount); + } + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void MapGeometryBuffer() + { + RenderHelper.MapSurfaceBuffer(_surfaceBuffer, _mesh, _extrusion); + RenderHelper.MapMeshGridBuffer(_meshGridBuffer, _mesh, _extrusion); + MapNormalsBuffer(); + } + + private void MapNormalsBuffer() + { + var area = RenderGeometryHelper.ComputeMeshSurfaceArea(_mesh); + var offset = RenderGeometryHelper.InterpolateOffsetByArea(area); + var normalLength = RenderGeometryHelper.InterpolateAxisLengthByArea(area); + + for (var i = 0; i < _mesh.Vertices.Count; i++) + { + var vertex = _mesh.Vertices[i]; + var buffer = _normalBuffers[i]; + var normal = RenderGeometryHelper.GetMeshVertexNormal(_mesh, i, _mesh.DistributionOfNormals); + + RenderHelper.MapNormalVectorBuffer(buffer, vertex + normal * (offset + _extrusion), normal, normalLength); + } + } + + private void UpdateEffects() + { + _surfaceBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + _meshGridBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + + _surfaceBuffer.EffectInstance.SetColor(_surfaceColor); + _meshGridBuffer.EffectInstance.SetColor(_meshColor); + _surfaceBuffer.EffectInstance.SetTransparency(_transparency); + + foreach (var normalBuffer in _normalBuffers) + { + normalBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + normalBuffer.EffectInstance.SetColor(_normalColor); + } + } + + public void UpdateSurfaceColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _surfaceColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateMeshGridColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _meshColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateNormalVectorColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _normalColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateExtrusion(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _extrusion = value; + _hasGeometryUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + + public void UpdateSurfaceVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawSurface = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateMeshGridVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawMeshGrid = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateNormalVectorVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawNormalVector = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(Mesh mesh) + { + _mesh = mesh; + _normalBuffers = Enumerable.Range(0, _mesh.Vertices.Count) + .Select(_ => new RenderingBufferStorage()) + .ToArray(); + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/PolylineVisualizationServer.cs b/source/RevitLookup/Core/Visualization/PolylineVisualizationServer.cs new file mode 100644 index 000000000..d296dec4c --- /dev/null +++ b/source/RevitLookup/Core/Visualization/PolylineVisualizationServer.cs @@ -0,0 +1,348 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class PolylineVisualizationServer : IDirectContext3DServer +{ + private IList _vertices = null!; //Cant be null after registration + private bool _hasEffectsUpdates = true; + private bool _hasGeometryUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + + private readonly RenderingBufferStorage _surfaceBuffer = new(); + private readonly RenderingBufferStorage _curveBuffer = new(); + private readonly List _normalsBuffers = new(1); + + private double _transparency; + private double _diameter; + + private Color _surfaceColor = Color.InvalidColorValue; + private Color _curveColor = Color.InvalidColorValue; + private Color _directionColor = Color.InvalidColorValue; + + private bool _drawCurve; + private bool _drawDirection; + private bool _drawSurface; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "Polyline visualization server"; + public string GetDescription() => "Polyline geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawSurface && _transparency > 0; + public Outline? GetBoundingBox(View view) => null; + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates || !_surfaceBuffer.IsValid() || !_curveBuffer.IsValid()) + { + MapGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawSurface) + { + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + DrawContext.FlushBuffer(_surfaceBuffer.VertexBuffer, + _surfaceBuffer.VertexBufferCount, + _surfaceBuffer.IndexBuffer, + _surfaceBuffer.IndexBufferCount, + _surfaceBuffer.VertexFormat, + _surfaceBuffer.EffectInstance, PrimitiveType.TriangleList, 0, + _surfaceBuffer.PrimitiveCount); + } + } + + if (_drawCurve) + { + DrawContext.FlushBuffer(_curveBuffer.VertexBuffer, + _curveBuffer.VertexBufferCount, + _curveBuffer.IndexBuffer, + _curveBuffer.IndexBufferCount, + _curveBuffer.VertexFormat, + _curveBuffer.EffectInstance, PrimitiveType.LineList, 0, + _curveBuffer.PrimitiveCount); + } + + if (_drawDirection) + { + foreach (var buffer in _normalsBuffers) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.LineList, 0, + buffer.PrimitiveCount); + } + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void MapGeometryBuffer() + { + RenderHelper.MapCurveSurfaceBuffer(_surfaceBuffer, _vertices, _diameter); + RenderHelper.MapCurveBuffer(_curveBuffer, _vertices, _diameter); + MapDirectionsBuffer(); + } + + private void MapDirectionsBuffer() + { + var verticalOffset = 0d; + + for (var i = 0; i < _vertices.Count - 1; i++) + { + var startPoint = _vertices[i]; + var endPoint = _vertices[i + 1]; + var centerPoint = (startPoint + endPoint) / 2; + var buffer = CreateNormalBuffer(i); + + var segmentVector = endPoint - startPoint; + var segmentLength = segmentVector.GetLength(); + var segmentDirection = segmentVector.Normalize(); + if (verticalOffset == 0) + { + verticalOffset = RenderGeometryHelper.InterpolateOffsetByDiameter(_diameter) + _diameter / 2d; + } + + var offsetVector = XYZ.BasisX.CrossProduct(segmentDirection).Normalize() * verticalOffset; + if (offsetVector.IsZeroLength()) + { + offsetVector = XYZ.BasisY.CrossProduct(segmentDirection).Normalize() * verticalOffset; + } + + if (offsetVector.Z < 0) + { + offsetVector = -offsetVector; + } + + var arrowLength = segmentLength > 1 ? 1d : segmentLength * 0.6; + var arrowOrigin = centerPoint + offsetVector - segmentDirection * (arrowLength / 2); + + RenderHelper.MapNormalVectorBuffer(buffer, arrowOrigin, segmentDirection, arrowLength); + } + } + + + private RenderingBufferStorage CreateNormalBuffer(int vertexIndex) + { + RenderingBufferStorage buffer; + if (_normalsBuffers.Count > vertexIndex) + { + buffer = _normalsBuffers[vertexIndex]; + } + else + { + buffer = new RenderingBufferStorage(); + _normalsBuffers.Add(buffer); + } + + return buffer; + } + + private void UpdateEffects() + { + _surfaceBuffer.EffectInstance ??= new EffectInstance(_surfaceBuffer.FormatBits); + _surfaceBuffer.EffectInstance.SetColor(_surfaceColor); + _surfaceBuffer.EffectInstance.SetTransparency(_transparency); + + _curveBuffer.EffectInstance ??= new EffectInstance(_curveBuffer.FormatBits); + _curveBuffer.EffectInstance.SetColor(_curveColor); + + foreach (var buffer in _normalsBuffers) + { + buffer.EffectInstance ??= new EffectInstance(buffer.FormatBits); + buffer.EffectInstance.SetColor(_directionColor); + } + } + + public void UpdateSurfaceColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _surfaceColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateCurveColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _curveColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateDirectionColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _directionColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateDiameter(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _diameter = value; + _hasGeometryUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + + public void UpdateSurfaceVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawSurface = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateCurveVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawCurve = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateDirectionVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawDirection = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(IList vertices) + { + _vertices = vertices; + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/SolidVisualizationServer.cs b/source/RevitLookup/Core/Visualization/SolidVisualizationServer.cs new file mode 100644 index 000000000..1c6b016e4 --- /dev/null +++ b/source/RevitLookup/Core/Visualization/SolidVisualizationServer.cs @@ -0,0 +1,309 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class SolidVisualizationServer : IDirectContext3DServer +{ + private Solid _solid = null!; //Cant be null after registration + private bool _hasEffectsUpdates = true; + private bool _hasGeometryUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + private readonly List _faceBuffers = new(4); + private readonly List _edgeBuffers = new(8); + + private double _transparency; + private double _scale; + + private Color _faceColor = Color.InvalidColorValue; + private Color _edgeColor = Color.InvalidColorValue; + + private bool _drawFace; + private bool _drawEdge; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "Solid visualization server"; + public string GetDescription() => "Solid geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawFace && _transparency > 0; + + public Outline GetBoundingBox(View view) + { + var boundingBox = _solid.GetBoundingBox(); + var minPoint = boundingBox.Transform.OfPoint(boundingBox.Min); + var maxPoint = boundingBox.Transform.OfPoint(boundingBox.Max); + + return new Outline(minPoint, maxPoint); + } + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates) + { + MapGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawFace) + { + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + foreach (var buffer in _faceBuffers) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.TriangleList, 0, + buffer.PrimitiveCount); + } + } + } + + if (_drawEdge) + { + foreach (var buffer in _edgeBuffers) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.LineList, 0, + buffer.PrimitiveCount); + } + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void MapGeometryBuffer() + { + var scaledSolid = RenderGeometryHelper.ScaleSolid(_solid, _scale); + + var faceIndex = 0; + foreach (Face face in scaledSolid.Faces) + { + var buffer = CreateOrUpdateBuffer(_faceBuffers, faceIndex++); + MapFaceBuffers(buffer, face); + } + + var edgeIndex = 0; + foreach (Edge edge in scaledSolid.Edges) + { + var buffer = CreateOrUpdateBuffer(_edgeBuffers, edgeIndex++); + MapEdgeBuffers(buffer, edge); + } + } + + private void MapFaceBuffers(RenderingBufferStorage buffer, Face face) + { + var mesh = face.Triangulate(); + RenderHelper.MapSurfaceBuffer(buffer, mesh, 0); + } + + private void MapEdgeBuffers(RenderingBufferStorage buffer, Edge edge) + { + var mesh = edge.Tessellate(); + RenderHelper.MapCurveBuffer(buffer, mesh); + } + + private RenderingBufferStorage CreateOrUpdateBuffer(List buffers, int index) + { + RenderingBufferStorage buffer; + if (buffers.Count > index) + { + buffer = buffers[index]; + } + else + { + buffer = new RenderingBufferStorage(); + buffers.Add(buffer); + } + + return buffer; + } + + private void UpdateEffects() + { + foreach (var buffer in _faceBuffers) + { + buffer.EffectInstance ??= new EffectInstance(buffer.FormatBits); + buffer.EffectInstance.SetColor(_faceColor); + buffer.EffectInstance.SetTransparency(_transparency); + } + + foreach (var buffer in _edgeBuffers) + { + buffer.EffectInstance ??= new EffectInstance(buffer.FormatBits); + buffer.EffectInstance.SetColor(_edgeColor); + } + } + + public void UpdateFaceColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _faceColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateEdgeColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _edgeColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateScale(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + _scale = value; + + lock (_renderLock) + { + _hasGeometryUpdates = true; + _hasEffectsUpdates = true; + _faceBuffers.Clear(); + _edgeBuffers.Clear(); + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateFaceVisibility(bool value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawFace = value; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateEdgeVisibility(bool value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawEdge = value; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(Solid solid) + { + _solid = solid; + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Visualization/XyzVisualizationServer.cs b/source/RevitLookup/Core/Visualization/XyzVisualizationServer.cs new file mode 100644 index 000000000..29f1fb261 --- /dev/null +++ b/source/RevitLookup/Core/Visualization/XyzVisualizationServer.cs @@ -0,0 +1,356 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.DB.DirectContext3D; +using Autodesk.Revit.DB.ExternalService; +using RevitLookup.Core.Visualization.Buffers; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.Core.Visualization.Helpers; + +namespace RevitLookup.Core.Visualization; + +public sealed class XyzVisualizationServer : IDirectContext3DServer +{ + private XYZ _point = null!; //Cant be null after registration + private bool _hasEffectsUpdates = true; + private bool _hasGeometryUpdates = true; + + private readonly Guid _guid = Guid.NewGuid(); + private readonly object _renderLock = new(); + + private readonly RenderingBufferStorage[] _planeBuffers = Enumerable.Range(0, 3) + .Select(_ => new RenderingBufferStorage()) + .ToArray(); + + private readonly RenderingBufferStorage[] _axisBuffers = Enumerable.Range(0, 3) + .Select(_ => new RenderingBufferStorage()) + .ToArray(); + + private readonly XYZ[] _normals = + [ + XYZ.BasisX, + XYZ.BasisY, + XYZ.BasisZ + ]; + + private double _transparency; + private double _axisLength; + + private Color _xColor = Color.InvalidColorValue; + private Color _yColor = Color.InvalidColorValue; + private Color _zColor = Color.InvalidColorValue; + + private bool _drawPlane; + private bool _drawXAxis; + private bool _drawYAxis; + private bool _drawZAxis; + + public Guid GetServerId() => _guid; + public string GetVendorId() => "RevitLookup"; + public string GetName() => "XYZ visualization server"; + public string GetDescription() => "XYZ geometry visualization"; + public ExternalServiceId GetServiceId() => ExternalServices.BuiltInExternalServices.DirectContext3DService; + public string GetApplicationId() => string.Empty; + public string GetSourceId() => string.Empty; + public bool UsesHandles() => false; + public bool CanExecute(View view) => true; + public bool UseInTransparentPass(View view) => _drawPlane && _transparency > 0; + + public Outline GetBoundingBox(View view) + { + var minPoint = new XYZ(_point.X - _axisLength, _point.Y - _axisLength, _point.Z - _axisLength); + var maxPoint = new XYZ(_point.X + _axisLength, _point.Y + _axisLength, _point.Z + _axisLength); + + return new Outline(minPoint, maxPoint); + } + + public void RenderScene(View view, DisplayStyle displayStyle) + { + lock (_renderLock) + { + try + { + if (_hasGeometryUpdates) + { + UpdateGeometryBuffer(); + _hasGeometryUpdates = false; + } + + if (_hasEffectsUpdates) + { + UpdateEffects(); + _hasEffectsUpdates = false; + } + + if (_drawXAxis) + { + RenderAxisBuffer(_axisBuffers[0]); + RenderPlaneBuffer(_planeBuffers[0]); + } + + if (_drawYAxis) + { + RenderAxisBuffer(_axisBuffers[1]); + RenderPlaneBuffer(_planeBuffers[1]); + } + + if (_drawZAxis) + { + RenderAxisBuffer(_axisBuffers[2]); + RenderPlaneBuffer(_planeBuffers[2]); + } + } + catch (Exception exception) + { + RenderFailed?.Invoke(this, new RenderFailedEventArgs + { + ExceptionObject = exception + }); + } + } + } + + private void RenderPlaneBuffer(RenderingBufferStorage buffer) + { + if (!_drawPlane) return; + + var isTransparentPass = DrawContext.IsTransparentPass(); + if (isTransparentPass && _transparency > 0 || !isTransparentPass && _transparency == 0) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.TriangleList, 0, + buffer.PrimitiveCount); + } + } + + private void RenderAxisBuffer(RenderingBufferStorage buffer) + { + DrawContext.FlushBuffer(buffer.VertexBuffer, + buffer.VertexBufferCount, + buffer.IndexBuffer, + buffer.IndexBufferCount, + buffer.VertexFormat, + buffer.EffectInstance, PrimitiveType.LineList, 0, + buffer.PrimitiveCount); + } + + private void UpdateGeometryBuffer() + { + MapNormalBuffer(); + MapPlaneBuffer(); + } + + private void MapNormalBuffer() + { + var normalExtendLength = _axisLength > 1 ? 0.8 : _axisLength * 0.8; + for (var i = 0; i < _normals.Length; i++) + { + var normal = _normals[i]; + var buffer = _axisBuffers[i]; + RenderHelper.MapNormalVectorBuffer(buffer, _point - normal * (_axisLength + normalExtendLength), normal, 2 * (_axisLength + normalExtendLength)); + } + } + + private void MapPlaneBuffer() + { + for (var i = 0; i < _normals.Length; i++) + { + var normal = _normals[i]; + var buffer = _planeBuffers[i]; + RenderHelper.MapSideBuffer(buffer, _point - normal * _axisLength, _point + normal * _axisLength); + } + } + + private void UpdateEffects() + { + foreach (var buffer in _planeBuffers) + { + buffer.EffectInstance ??= new EffectInstance(buffer.FormatBits); + buffer.EffectInstance.SetTransparency(_transparency); + } + + _planeBuffers[0].EffectInstance!.SetColor(_xColor); + _planeBuffers[1].EffectInstance!.SetColor(_yColor); + _planeBuffers[2].EffectInstance!.SetColor(_zColor); + + foreach (var buffer in _axisBuffers) + { + buffer.EffectInstance ??= new EffectInstance(buffer.FormatBits); + } + + _axisBuffers[0].EffectInstance!.SetColor(_xColor); + _axisBuffers[1].EffectInstance!.SetColor(_yColor); + _axisBuffers[2].EffectInstance!.SetColor(_zColor); + } + + public void UpdateXColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _xColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateYColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _yColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateZColor(Color value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _zColor = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateAxisLength(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _axisLength = value; + _hasGeometryUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateTransparency(double value) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _transparency = value; + _hasEffectsUpdates = true; + + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdatePlaneVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawPlane = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateXAxisVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawXAxis = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateYAxisVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawYAxis = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void UpdateZAxisVisibility(bool visible) + { + var uiDocument = Context.ActiveUiDocument; + if (uiDocument is null) return; + + lock (_renderLock) + { + _drawZAxis = visible; + uiDocument.UpdateAllOpenViews(); + } + } + + public void Register(XYZ point) + { + _point = point; + + RevitShell.ActionEventHandler.Raise(application => + { + if (application.ActiveUIDocument is null) return; + + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + var serverIds = directContextService.GetActiveServerIds(); + + directContextService.AddServer(this); + serverIds.Add(GetServerId()); + directContextService.SetActiveServers(serverIds); + + application.ActiveUIDocument.UpdateAllOpenViews(); + }); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(application => + { + var directContextService = (MultiServerService) ExternalServiceRegistry.GetService(ExternalServices.BuiltInExternalServices.DirectContext3DService); + directContextService.RemoveServer(GetServerId()); + + application.ActiveUIDocument?.UpdateAllOpenViews(); + }); + } + + public event EventHandler? RenderFailed; +} \ No newline at end of file diff --git a/source/RevitLookup/Host.cs b/source/RevitLookup/Host.cs index 875b6d222..ba39ad32d 100644 --- a/source/RevitLookup/Host.cs +++ b/source/RevitLookup/Host.cs @@ -3,18 +3,22 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; using RevitLookup.Config; using RevitLookup.Services; -using RevitLookup.Services.Contracts; -using RevitLookup.ViewModels.Contracts; -using RevitLookup.ViewModels.Dialogs; -using RevitLookup.ViewModels.Dialogs.Visualization; -using RevitLookup.ViewModels.Pages; -using RevitLookup.Views; -using RevitLookup.Views.Dialogs; -using RevitLookup.Views.Dialogs.Visualization; -using RevitLookup.Views.Pages; +using RevitLookup.Services.Appearance; +using RevitLookup.Services.Application; +using RevitLookup.Services.Settings; +using RevitLookup.Services.Summary; +using RevitLookup.UI.Framework.Services; +using RevitLookup.UI.Framework.Services.Presentation; using Wpf.Ui; +using Wpf.Ui.Abstractions; +using SoftwareUpdateService = RevitLookup.Services.Settings.SoftwareUpdateService; namespace RevitLookup; @@ -23,7 +27,7 @@ namespace RevitLookup; /// public static class Host { - private static IHost _host; + private static IHost? _host; /// /// Starts the host and configures the application's services @@ -32,8 +36,13 @@ public static void Start() { var builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(new HostApplicationBuilderSettings { - ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly()!.Location), - DisableDefaults = true + ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + DisableDefaults = true, +#if RELEASE + EnvironmentName = Environments.Development +#else + EnvironmentName = Environments.Development +#endif }); //Logging @@ -41,87 +50,48 @@ public static void Start() builder.Logging.AddSerilogConfiguration(); //Configuration - builder.Services.AddOptions(builder.Configuration); + builder.Services.AddApplicationOptions(); + builder.Services.AddAssemblyOptions(); + builder.Services.AddFolderOptions(); + builder.Services.AddSerializerOptions(); - //Application services - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddHostedService(); - - //UI services + //Frontend services + builder.Services.AddScoped(); builder.Services.AddScoped(); - builder.Services.AddScoped(); builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); - //Views - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); - builder.Services.AddTransient(); - builder.Services.AddScoped(); - builder.Services.AddScoped(); + //MVVM services + builder.Services.RegisterViews(); + builder.Services.RegisterViewModels(); - //Dialogs - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); + //Application services + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddHostedService(); - //Startup view - builder.Services.AddTransient(); + //Services + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddScoped(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); _host = builder.Build(); _host.Start(); } - /// - /// Starts the host proxy and configures the application's services - /// - public static void StartProxy(IHost host) - { - _host = host; - host.Start(); - } - /// /// Stops the host and handle services /// public static void Stop() { - _host.StopAsync().GetAwaiter().GetResult(); + _host!.StopAsync().GetAwaiter().GetResult(); } /// @@ -131,6 +101,6 @@ public static void Stop() /// There is no service of type public static T GetService() where T : class { - return _host.Services.GetRequiredService(); + return _host!.Services.GetRequiredService(); } } \ No newline at end of file diff --git a/source/RevitLookup/Mappers/DecompositionResultMapper.cs b/source/RevitLookup/Mappers/DecompositionResultMapper.cs new file mode 100644 index 000000000..2d3d59fbf --- /dev/null +++ b/source/RevitLookup/Mappers/DecompositionResultMapper.cs @@ -0,0 +1,12 @@ +using LookupEngine.Abstractions; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using Riok.Mapperly.Abstractions; + +namespace RevitLookup.Mappers; + +[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.Source)] +public static partial class DecompositionResultMapper +{ + public static partial ObservableDecomposedObject Convert(DecomposedObject decomposedObject); + public static partial ObservableDecomposedMember Convert(DecomposedMember decomposedMember); +} \ No newline at end of file diff --git a/source/RevitLookup/RevitLookup.csproj b/source/RevitLookup/RevitLookup.csproj index c7e2a03da..c9cd4ad69 100644 --- a/source/RevitLookup/RevitLookup.csproj +++ b/source/RevitLookup/RevitLookup.csproj @@ -2,37 +2,11 @@ true - CS8826 - disable - latest - x64 - true true Debug R21;Debug R22;Debug R23;Debug R24;Debug R25 $(Configurations);Release R21;Release R22;Release R23;Release R24;Release R25 - - 2021 - net48 - - - 2022 - net48 - - - 2023 - net48 - - - 2024 - net48 - - - 2025 - net8.0-windows - - Program C:\Program Files\Autodesk\Revit $(RevitVersion)\Revit.exe @@ -45,76 +19,46 @@ - - - - - - - - - + + + + + + + + + - + + - + + - - - - - - - + + + + + + + + - - - - - - - - - - - - - ResXFileCodeGenerator - Colors.Designer.cs - - - ResXFileCodeGenerator - Colors.Designer.cs - PublicResXFileCodeGenerator - - - - - - True - True - Colors.resx - - - True - True - Colors.resx - diff --git a/source/RevitLookup/RevitLookup.csproj.DotSettings b/source/RevitLookup/RevitLookup.csproj.DotSettings index 7057a74b6..c36c272ac 100644 --- a/source/RevitLookup/RevitLookup.csproj.DotSettings +++ b/source/RevitLookup/RevitLookup.csproj.DotSettings @@ -1,5 +1,4 @@ - - No \ No newline at end of file + + UI + No \ No newline at end of file diff --git a/source/RevitLookup/Services/Appearance/ThemeWatcherService.cs b/source/RevitLookup/Services/Appearance/ThemeWatcherService.cs new file mode 100644 index 000000000..f3987cacb --- /dev/null +++ b/source/RevitLookup/Services/Appearance/ThemeWatcherService.cs @@ -0,0 +1,156 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows; +using Autodesk.Revit.UI; +using Autodesk.Revit.UI.Events; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Core; +using Wpf.Ui; +using Wpf.Ui.Appearance; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Services.Appearance; + +public sealed class ThemeWatcherService(ISettingsService settingsService) : IThemeWatcherService +{ +#if REVIT2024_OR_GREATER + private bool _isWatching; +#endif + + private readonly List _observedElements = []; + + public void Initialize() + { + UiApplication.Current.Resources = new ResourceDictionary + { + Source = new Uri("pack://application:,,,/RevitLookup;component/Styles/App.Resources.xaml", UriKind.Absolute) + }; + + ApplicationThemeManager.Apply(settingsService.GeneralSettings.Theme, settingsService.GeneralSettings.Background); + ApplicationThemeManager.Changed += ApplicationThemeManagerOnChanged; + } + + public void Watch() + { + var theme = settingsService.GeneralSettings.Theme; +#if REVIT2024_OR_GREATER + if (settingsService.GeneralSettings.Theme == ApplicationTheme.Auto) + { + theme = GetRevitTheme(); + + if (!_isWatching) + { + RevitShell.ActionEventHandler.Raise(_ => Context.UiApplication.ThemeChanged += OnRevitThemeChanged); + _isWatching = true; + } + } +#endif + ApplicationThemeManager.Apply(theme, settingsService.GeneralSettings.Background); + UpdateBackground(theme); + } + + public void Watch(FrameworkElement frameworkElement) + { + ApplicationThemeManager.Apply(frameworkElement); + frameworkElement.Loaded += OnWatchedElementLoaded; + frameworkElement.Unloaded += OnWatchedElementUnloaded; + } + + public void Unwatch() + { +#if REVIT2024_OR_GREATER + if (!_isWatching) return; + + RevitShell.ActionEventHandler.Raise(_ => Context.UiApplication.ThemeChanged -= OnRevitThemeChanged); + _isWatching = false; +#endif + } + +#if REVIT2024_OR_GREATER + private void OnRevitThemeChanged(object? sender, ThemeChangedEventArgs args) + { + if (args.ThemeChangedType != ThemeType.UITheme) return; + + var theme = GetRevitTheme(); + ApplicationThemeManager.Apply(theme, settingsService.GeneralSettings.Background); + UpdateBackground(theme); + } + + private static ApplicationTheme GetRevitTheme() + { + return UIThemeManager.CurrentTheme switch + { + UITheme.Light => ApplicationTheme.Light, + UITheme.Dark => ApplicationTheme.Dark, + _ => throw new ArgumentOutOfRangeException() + }; + } +#endif + + private void ApplicationThemeManagerOnChanged(ApplicationTheme applicationTheme, Color accent) + { + foreach (var frameworkElement in _observedElements) + { + UpdateDictionary(frameworkElement); + } + } + + private void OnWatchedElementLoaded(object sender, RoutedEventArgs e) + { + var element = (FrameworkElement) sender; + _observedElements.Add(element); + + if (element.Resources.MergedDictionaries[0].Source.OriginalString != UiApplication.Current.Resources.MergedDictionaries[0].Source.OriginalString) + { + UpdateDictionary(element); + } + } + + private void OnWatchedElementUnloaded(object sender, RoutedEventArgs e) + { + var element = (FrameworkElement) sender; + _observedElements.Remove(element); + } + + private static void UpdateDictionary(FrameworkElement frameworkElement) + { + var themedResources = frameworkElement.Resources.MergedDictionaries + .Where(dictionary => dictionary.Source.OriginalString.Contains("revitlookup.ui;", StringComparison.OrdinalIgnoreCase)) + .ToArray(); + + frameworkElement.Resources.MergedDictionaries.Insert(0, UiApplication.Current.Resources.MergedDictionaries[0]); + frameworkElement.Resources.MergedDictionaries.Insert(1, UiApplication.Current.Resources.MergedDictionaries[1]); + + foreach (var themedResource in themedResources) + { + frameworkElement.Resources.MergedDictionaries.Remove(themedResource); + } + } + + private void UpdateBackground(ApplicationTheme theme) + { + foreach (var window in _observedElements.Select(Window.GetWindow).Distinct()) + { + WindowBackgroundManager.UpdateBackground(window, theme, settingsService.GeneralSettings.Background); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Application/HostBackgroundService.cs b/source/RevitLookup/Services/Application/HostBackgroundService.cs new file mode 100644 index 000000000..6c93bd1d3 --- /dev/null +++ b/source/RevitLookup/Services/Application/HostBackgroundService.cs @@ -0,0 +1,87 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.IO; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Common.Tools; + +namespace RevitLookup.Services.Application; + +/// +/// Provides life cycle processes for the application +/// +public sealed class HostBackgroundService( + ISettingsService settingsService, + ISoftwareUpdateService updateService, + ILogger logger) + : IHostedService +{ + public Task StartAsync(CancellationToken cancellationToken) + { + LoadSettings(); + _ = CheckUpdatesAsync(); + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + SaveSettings(); + UpdateSoftware(); + return Task.CompletedTask; + } + + private async Task CheckUpdatesAsync() + { + try + { + var hasUpdates = await updateService.CheckUpdatesAsync(); + if (!hasUpdates) return; + + logger.LogInformation("RevitLookup {Version} is available to download", updateService.NewVersion); + } + catch (Exception exception) + { + logger.LogError(exception, "Update service error"); + } + } + + private void UpdateSoftware() + { + if (!File.Exists(updateService.LocalFilePath)) return; + + logger.LogInformation("Installing RevitLookup {Version} version", updateService.NewVersion); + ProcessTasks.StartShell(updateService.LocalFilePath!); + } + + private void SaveSettings() + { + logger.LogInformation("Saving settings"); + settingsService.SaveSettings(); + } + + private void LoadSettings() + { + logger.LogInformation("Loading settings"); + settingsService.LoadSettings(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Application/RevitLookupUiService.cs b/source/RevitLookup/Services/Application/RevitLookupUiService.cs new file mode 100644 index 000000000..3dff5df6d --- /dev/null +++ b/source/RevitLookup/Services/Application/RevitLookupUiService.cs @@ -0,0 +1,261 @@ +using System.Collections; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Threading; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.UI.Framework.Views.Windows; +using Wpf.Ui; + +namespace RevitLookup.Services.Application; + +public sealed class RevitLookupUiService : IRevitLookupUiService +{ + private static readonly Dispatcher Dispatcher; + private UiServiceImpl _uiService = null!; //Late init in constructor + + static RevitLookupUiService() + { + var uiThread = new Thread(Dispatcher.Run); + uiThread.SetApartmentState(ApartmentState.STA); + uiThread.Start(); + + Dispatcher = EnsureDispatcherStart(uiThread); + } + + public RevitLookupUiService(IServiceScopeFactory scopeFactory) + { + if (Dispatcher.CheckAccess()) + { + _uiService = new UiServiceImpl(scopeFactory); + } + else + { + Dispatcher.Invoke(() => _uiService = new UiServiceImpl(scopeFactory)); + } + } + + public ILookupServiceDependsStage Decompose(KnownDecompositionObject decompositionObject) + { + if (Dispatcher.CheckAccess()) + { + _uiService.Decompose(decompositionObject); + } + else + { + Dispatcher.Invoke(() => _uiService.Decompose(decompositionObject)); + } + + return this; + } + + public ILookupServiceDependsStage Decompose(object? obj) + { + if (Dispatcher.CheckAccess()) + { + _uiService.Decompose(obj); + } + else + { + Dispatcher.Invoke(() => _uiService.Decompose(obj)); + } + + return this; + } + + public ILookupServiceDependsStage Decompose(IEnumerable objects) + { + if (Dispatcher.CheckAccess()) + { + _uiService.Decompose(objects); + } + else + { + Dispatcher.Invoke(() => _uiService.Decompose(objects)); + } + + return this; + } + + public ILookupServiceDependsStage Decompose(ObservableDecomposedObject decomposedObject) + { + if (Dispatcher.CheckAccess()) + { + _uiService.Decompose(decomposedObject); + } + else + { + Dispatcher.Invoke(() => _uiService.Decompose(decomposedObject)); + } + + return this; + } + + public ILookupServiceDependsStage Decompose(List decomposedObjects) + { + if (Dispatcher.CheckAccess()) + { + _uiService.Decompose(decomposedObjects); + } + else + { + Dispatcher.Invoke(() => _uiService.Decompose(decomposedObjects)); + } + + return this; + } + + public ILookupServiceShowStage DependsOn(Window parent) + { + if (Dispatcher.CheckAccess()) + { + _uiService.DependsOn(parent); + } + else + { + Dispatcher.Invoke(() => _uiService.DependsOn(parent)); + } + + return this; + } + + public ILookupServiceRunStage Show() where T : Page + { + if (Dispatcher.CheckAccess()) + { + _uiService.Show(); + } + else + { + Dispatcher.Invoke(() => _uiService.Show()); + } + + return this; + } + + public void RunService(Action handler) where T : class + { + if (Dispatcher.CheckAccess()) + { + _uiService.RunService(handler); + } + else + { + Dispatcher.Invoke(() => _uiService.RunService(handler)); + } + } + + private static Dispatcher EnsureDispatcherStart(Thread thread) + { + Dispatcher? dispatcher = null; + SpinWait spinWait = new(); + while (dispatcher is null) + { + spinWait.SpinOnce(); + dispatcher = Dispatcher.FromThread(thread); + } + + // We must yield + // Sometimes the Dispatcher is unavailable for current thread + Thread.Sleep(1); + + return dispatcher; + } + + private sealed class UiServiceImpl + { + private Window? _parent; + private readonly Task _activeTask = Task.CompletedTask; + private readonly IServiceScope _scope; + private readonly IVisualDecompositionService _decompositionService; + private readonly INavigationService _navigationService; + private readonly Window _host; + + public UiServiceImpl(IServiceScopeFactory scopeFactory) + { + _scope = scopeFactory.CreateScope(); + + _host = _scope.ServiceProvider.GetRequiredService(); + _decompositionService = _scope.ServiceProvider.GetRequiredService(); + _navigationService = _scope.ServiceProvider.GetRequiredService(); + + _host.Closed += (_, _) => _scope.Dispose(); + } + + public void Decompose(KnownDecompositionObject decompositionObject) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decompositionObject), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void Decompose(object? obj) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(obj), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void Decompose(IEnumerable objects) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(objects), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void Decompose(ObservableDecomposedObject decomposedObject) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObject), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void Decompose(List decomposedObjects) + { + _activeTask.ContinueWith(_ => _decompositionService.VisualizeDecompositionAsync(decomposedObjects), TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void DependsOn(Window parent) + { + _parent = parent; + } + + public void Show() where T : Page + { + _activeTask.ContinueWith(_ => + { + ShowHost(false); + _navigationService.Navigate(typeof(T)); + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + + public void RunService(Action handler) where T : class + { + _activeTask.ContinueWith(_ => InvokeService(handler), TaskScheduler.FromCurrentSynchronizationContext()); + } + + private void InvokeService(Action handler) where T : class + { + var service = _scope.ServiceProvider.GetRequiredService(); + handler.Invoke(service); + } + + private void ShowHost(bool modal) + { + if (_parent is null) + { + _host.WindowStartupLocation = WindowStartupLocation.CenterScreen; + } + else + { + _host.WindowStartupLocation = WindowStartupLocation.Manual; + _host.Left = _parent.Left + 47; + _host.Top = _parent.Top + 49; + } + + if (modal) + { + _host.ShowDialog(); + } + else + { + _host.Show(Context.UiApplication.MainWindowHandle); + } + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Application/RevitRibbonService.cs b/source/RevitLookup/Services/Application/RevitRibbonService.cs new file mode 100644 index 000000000..b561e57d9 --- /dev/null +++ b/source/RevitLookup/Services/Application/RevitRibbonService.cs @@ -0,0 +1,93 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.UI; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Commands; +using RevitLookup.Core; +using UIFramework; + +namespace RevitLookup.Services.Application; + +public sealed class RevitRibbonService(ISettingsService settingsService) +{ + private readonly List _createdPanels = new(2); + + public void CreateRibbon() + { + RevitShell.ActionEventHandler.Raise(_ => + { + if (_createdPanels.Count == 0) + { + CreatePanels(); + return; + } + + RemovePanels(); + CreatePanels(); + ShortcutsHelper.LoadCommands(); + }); + } + + private void CreatePanels() + { + var application = Context.UiControlledApplication; + var addinsPanel = application.CreatePanel("Revit Lookup"); + var pullButton = addinsPanel.AddPullDownButton("RevitLookupButton", "RevitLookup"); + pullButton.SetImage("/RevitLookup;component/Resources/Images/RibbonIcon16.png"); + pullButton.SetLargeImage("/RevitLookup;component/Resources/Images/RibbonIcon32.png"); + + pullButton.AddPushButton("Dashboard"); + if (!settingsService.GeneralSettings.UseModifyTab) + { + pullButton.AddPushButton("Snoop Selection"); + } + + pullButton.AddPushButton("Snoop Active view"); + pullButton.AddPushButton("Snoop Document"); + pullButton.AddPushButton("Snoop Database"); + pullButton.AddPushButton("Snoop Face"); + pullButton.AddPushButton("Snoop Edge"); + pullButton.AddPushButton("Snoop Point"); + pullButton.AddPushButton("Snoop Linked element"); + pullButton.AddPushButton("Search Elements"); + pullButton.AddPushButton("Event monitor"); + + _createdPanels.Add(addinsPanel); + if (!settingsService.GeneralSettings.UseModifyTab) return; + + var modifyPanel = application.CreatePanel("Revit Lookup", "Modify"); + modifyPanel.AddPushButton(" Snoop \nSelection") + .SetImage("/RevitLookup;component/Resources/Images/RibbonIcon16.png") + .SetLargeImage("/RevitLookup;component/Resources/Images/RibbonIcon32.png"); + + _createdPanels.Add(modifyPanel); + } + + private void RemovePanels() + { + foreach (var ribbonPanel in _createdPanels) + { + ribbonPanel.RemovePanel(); + } + + _createdPanels.Clear(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Settings/SettingsService.cs b/source/RevitLookup/Services/Settings/SettingsService.cs new file mode 100644 index 000000000..8bbf99000 --- /dev/null +++ b/source/RevitLookup/Services/Settings/SettingsService.cs @@ -0,0 +1,185 @@ +using System.IO; +using System.Text.Json; +using System.Windows.Media; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using RevitLookup.Abstractions.Models.Settings; +using RevitLookup.Abstractions.Options; +using RevitLookup.Abstractions.Services.Settings; +using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Services.Settings; + +public sealed class SettingsService( + IOptions foldersOptions, + IOptions jsonOptions, + ILogger logger) + : ISettingsService +{ + private GeneralSettings? _generalSettings; + private RenderSettings? _renderSettings; + + public GeneralSettings GeneralSettings => _generalSettings ?? throw new InvalidOperationException("Settings is not loaded."); + public RenderSettings RenderSettings => _renderSettings ?? throw new InvalidOperationException("Settings is not loaded."); + + public void SaveSettings() + { + SaveGeneralSettings(); + SaveRenderSettings(); + } + + public void LoadSettings() + { + LoadGeneralSettings(); + LoadRenderSettings(); + } + + private void SaveGeneralSettings() + { + var path = foldersOptions.Value.GeneralSettingsPath; + if (!File.Exists(path)) Directory.CreateDirectory(Path.GetDirectoryName(path)!); + + var json = JsonSerializer.Serialize(_generalSettings, jsonOptions.Value); + File.WriteAllText(path, json); + } + + private void SaveRenderSettings() + { + var path = foldersOptions.Value.RenderSettingsPath; + if (!File.Exists(path)) Directory.CreateDirectory(Path.GetDirectoryName(path)!); + + var json = JsonSerializer.Serialize(_renderSettings, jsonOptions.Value); + File.WriteAllText(path, json); + } + + private void LoadGeneralSettings() + { + var path = foldersOptions.Value.GeneralSettingsPath; + if (!File.Exists(path)) + { + ResetGeneralSettings(); + return; + } + + try + { + using var config = File.OpenRead(path); + _generalSettings = JsonSerializer.Deserialize(config, jsonOptions.Value); + } + catch (Exception exception) + { + logger.LogError(exception, "General settings loading error"); + } + } + + private void LoadRenderSettings() + { + var path = foldersOptions.Value.RenderSettingsPath; + if (!File.Exists(path)) + { + ResetRenderSettings(); + return; + } + + try + { + using var config = File.OpenRead(path); + _renderSettings = JsonSerializer.Deserialize(config, jsonOptions.Value); + } + catch (Exception exception) + { + logger.LogError(exception, "General settings loading error"); + } + } + + public void ResetGeneralSettings() + { + _generalSettings = new GeneralSettings + { + Theme = ApplicationTheme.Light, + Background = WindowBackdropType.None, + Transition = Transition.None, + IncludeStatic = true, + IncludeEvents = true, + UseHardwareRendering = true + }; + } + + public void ResetRenderSettings() + { + _renderSettings = new RenderSettings + { + BoundingBoxSettings = new BoundingBoxVisualizationSettings + { + Transparency = 60, + SurfaceColor = Colors.DodgerBlue, + EdgeColor = Color.FromArgb(255, 30, 81, 255), + AxisColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowEdge = true, + ShowAxis = true + }, + FaceSettings = new FaceVisualizationSettings + { + Transparency = 20, + Extrusion = 1, + MinExtrusion = 1, + SurfaceColor = Colors.DodgerBlue, + MeshColor = Color.FromArgb(255, 30, 81, 255), + NormalVectorColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowMeshGrid = true, + ShowNormalVector = true + }, + MeshSettings = new MeshVisualizationSettings + { + Transparency = 20, + Extrusion = 1, + MinExtrusion = 1, + SurfaceColor = Colors.DodgerBlue, + MeshColor = Color.FromArgb(255, 30, 81, 255), + NormalVectorColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowMeshGrid = true, + ShowNormalVector = true + }, + PolylineSettings = new PolylineVisualizationSettings + { + Transparency = 20, + Diameter = 2, + MinThickness = 0.1, + SurfaceColor = Colors.DodgerBlue, + CurveColor = Color.FromArgb(255, 30, 81, 255), + DirectionColor = Color.FromArgb(255, 255, 89, 30), + ShowSurface = true, + ShowCurve = true, + ShowDirection = true + }, + SolidSettings = new SolidVisualizationSettings + { + Transparency = 20, + Scale = 1, + FaceColor = Colors.DodgerBlue, + EdgeColor = Color.FromArgb(255, 30, 81, 255), + ShowFace = true, + ShowEdge = true + }, + XyzSettings = new XyzVisualizationSettings + { + Transparency = 0, + AxisLength = 6, + MinAxisLength = 0.1, + XColor = Color.FromArgb(255, 30, 227, 255), + YColor = Color.FromArgb(255, 30, 144, 255), + ZColor = Color.FromArgb(255, 30, 81, 255), + ShowPlane = true, + ShowXAxis = true, + ShowYAxis = true, + ShowZAxis = true + } + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Settings/SoftwareUpdateService.cs b/source/RevitLookup/Services/Settings/SoftwareUpdateService.cs new file mode 100644 index 000000000..0a8cf273b --- /dev/null +++ b/source/RevitLookup/Services/Settings/SoftwareUpdateService.cs @@ -0,0 +1,129 @@ +using System.IO; +using System.Net.Http; +using System.Text.Json; +using System.Text.RegularExpressions; +using Microsoft.Extensions.Options; +using RevitLookup.Abstractions.Models.GitHub; +using RevitLookup.Abstractions.Options; +using RevitLookup.Abstractions.Services.Settings; + +namespace RevitLookup.Services.Settings; + +public sealed class SoftwareUpdateService( + IOptions assemblyOptions, + IOptions foldersOptions) + : ISoftwareUpdateService +{ + private string? _downloadUrl; + private readonly AssemblyOptions _assemblyOptions = assemblyOptions.Value; + private readonly FoldersOptions _folderOptions = foldersOptions.Value; + private readonly Regex _versionRegex = new(@"(\d+\.)+\d+", RegexOptions.Compiled); + + public string? NewVersion { get; private set; } + public string? ReleaseNotesUrl { get; private set; } + public string? LocalFilePath { get; private set; } + public DateTime? LatestCheckDate { get; private set; } + + public async Task CheckUpdatesAsync() + { + LatestCheckDate = DateTime.Now; + + if (CheckExistingInstaller()) return true; + + var releases = await FetchGithubRepositoryAsync(); + if (releases.Count == 0) return false; + + var latestRelease = releases + .Where(response => !response.Draft) + .Where(response => !response.PreRelease) +#if NETCOREAPP + .MaxBy(release => release.PublishedDate); +#else + .OrderByDescending(release => release.PublishedDate) + .FirstOrDefault(); +#endif + + if (latestRelease is null) return false; + ReleaseNotesUrl = latestRelease.Url; + + var newVersionTag = FindNewServerVersion(latestRelease); + if (newVersionTag is null) return false; + if (newVersionTag <= _assemblyOptions.Version) return false; + + NewVersion = newVersionTag.ToString(3); + + var newVersionFileName = Path.GetFileName(_downloadUrl!); + var newVersionPath = Path.Combine(_folderOptions.DownloadsFolder, newVersionFileName); + if (File.Exists(newVersionPath)) + { + LocalFilePath = newVersionPath; + } + + return true; + } + + public async Task DownloadUpdate() + { + Directory.CreateDirectory(_folderOptions.DownloadsFolder); + var fileName = Path.Combine(_folderOptions.DownloadsFolder, Path.GetFileName(_downloadUrl)!); + + using var httpClient = new HttpClient(); + var response = await httpClient.GetStreamAsync(_downloadUrl); + +#if NETCOREAPP + await using var fileStream = new FileStream(fileName, FileMode.Create); +#else + using var fileStream = new FileStream(fileName, FileMode.Create); +#endif + await response.CopyToAsync(fileStream); + + LocalFilePath = fileName; + } + + private Version? FindNewServerVersion(GitHubResponse latestRelease) + { + if (latestRelease.Assets is null) return null; + + Version? newVersionTag = null; + foreach (var asset in latestRelease.Assets) + { + if (asset.Name is null) continue; + + var match = _versionRegex.Match(asset.Name); + if (!match.Success) continue; + if (!match.Value.StartsWith(_assemblyOptions.Version.Major.ToString())) continue; + if (!_assemblyOptions.HasAdminAccess && asset.Name.Contains("MultiUser")) continue; + + newVersionTag = new Version(match.Value); + _downloadUrl = asset.DownloadUrl; + break; + } + + return newVersionTag; + } + + private bool CheckExistingInstaller() + { + if (string.IsNullOrEmpty(LocalFilePath)) return false; + if (!File.Exists(LocalFilePath)) return false; + + var fileName = Path.GetFileName(LocalFilePath)!; + if (NewVersion is null) return false; + if (!fileName.Contains(NewVersion)) return false; + + return true; + } + + private static async Task> FetchGithubRepositoryAsync() + { + string releasesJson; + using (var gitHubClient = new HttpClient()) + { + gitHubClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", $"RevitLookup-{Guid.NewGuid().ToString()}"); + releasesJson = await gitHubClient.GetStringAsync("https://api.github.com/repos/jeremytammik/RevitLookup/releases"); + } + + var responses = JsonSerializer.Deserialize>(releasesJson); + return responses ?? []; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Summary/DecompositionService.cs b/source/RevitLookup/Services/Summary/DecompositionService.cs new file mode 100644 index 000000000..55e1a9e5c --- /dev/null +++ b/source/RevitLookup/Services/Summary/DecompositionService.cs @@ -0,0 +1,88 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using LookupEngine; +using LookupEngine.Options; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Core; +using RevitLookup.Core.Decomposition; +using RevitLookup.Mappers; + +namespace RevitLookup.Services.Summary; + +[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] +[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] +public sealed class DecompositionService(ISettingsService settingsService) : IDecompositionService +{ + public async Task DecomposeAsync(object obj) + { + var options = CreateDecomposeMembersOptions(); + return await RevitShell.AsyncObjectHandler.RaiseAsync(_ => + { + var result = LookupComposer.Decompose(obj, options); + return DecompositionResultMapper.Convert(result); + }); + } + + public async Task> DecomposeAsync(IEnumerable objects) + { + var options = CreateDecomposeOptions(); + return await RevitShell.AsyncObjectsHandler.RaiseAsync(_ => + { + var capacity = objects is ICollection collection ? collection.Count : 4; + var decomposedObjects = new List(capacity); + foreach (var obj in objects) + { + var decomposedObject = LookupComposer.DecomposeObject(obj, options); + decomposedObjects.Add(DecompositionResultMapper.Convert(decomposedObject)); + } + + return decomposedObjects; + }); + } + + public async Task> DecomposeMembersAsync(ObservableDecomposedObject decomposedObject) + { + var options = CreateDecomposeMembersOptions(); + return await RevitShell.AsyncMembersHandler.RaiseAsync(_ => + { + var decomposedMembers = LookupComposer.DecomposeMembers(decomposedObject.RawValue, options); + var members = new List(decomposedMembers.Count); + + foreach (var decomposedMember in decomposedMembers) + { + members.Add(DecompositionResultMapper.Convert(decomposedMember)); + } + + return members; + }); + } + + private static DecomposeOptions CreateDecomposeOptions() + { + return new DecomposeOptions + { + Context = Context.ActiveDocument!, //TODO: replace + EnableRedirection = true, + TypeResolver = DescriptorsMap.FindDescriptor + }; + } + + private DecomposeOptions CreateDecomposeMembersOptions() + { + return new DecomposeOptions + { + Context = Context.ActiveDocument!, //TODO: replace + IncludeRoot = settingsService.GeneralSettings.IncludeRootHierarchy, + IncludeFields = settingsService.GeneralSettings.IncludeFields, + IncludeEvents = settingsService.GeneralSettings.IncludeEvents, + IncludeUnsupported = settingsService.GeneralSettings.IncludeUnsupported, + IncludePrivateMembers = settingsService.GeneralSettings.IncludePrivate, + IncludeStaticMembers = settingsService.GeneralSettings.IncludeStatic, + EnableExtensions = settingsService.GeneralSettings.IncludeExtensions, + EnableRedirection = true, + TypeResolver = DescriptorsMap.FindDescriptor + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Summary/EventsMonitoringService.cs b/source/RevitLookup/Services/Summary/EventsMonitoringService.cs new file mode 100644 index 000000000..a9c6d9bde --- /dev/null +++ b/source/RevitLookup/Services/Summary/EventsMonitoringService.cs @@ -0,0 +1,123 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics; +using System.Reflection; +using Autodesk.Revit.UI; +using Microsoft.Extensions.Logging; +using RevitLookup.Core; + +namespace RevitLookup.Services.Summary; + +public sealed class EventsMonitoringService(ILogger logger) +{ + private Action? _callback; + private readonly Dictionary _handlersMap = new(16); + + private readonly Assembly[] _assemblies = AppDomain.CurrentDomain + .GetAssemblies() + .Where(assembly => + { + var name = assembly.GetName().Name; + return name is "RevitAPI" or "RevitAPIUI"; + }) + .Take(2) + .ToArray(); + + private readonly List _denyList = + [ + nameof(UIApplication.Idling), + nameof(Autodesk.Revit.ApplicationServices.Application.ProgressChanged) + ]; + + public void RegisterEventInvocationCallback(Action callback) + { + _callback = callback; + RevitShell.ActionEventHandler.Raise(Subscribe); + } + + public void Unregister() + { + RevitShell.ActionEventHandler.Raise(Unsubscribe); + } + + private void Subscribe(UIApplication uiApplication) + { + if (_handlersMap.Count > 0) return; + + foreach (var dll in _assemblies) + foreach (var type in dll.GetTypes()) + foreach (var eventInfo in type.GetEvents()) + { + if (_denyList.Contains(eventInfo.Name)) continue; + + var targets = FindValidTargets(eventInfo.ReflectedType); + if (targets.Length == 0) + { + logger.LogDebug("Missing target: {EventType}.{EventName}", eventInfo.ReflectedType, eventInfo.Name); + break; + } + + var methodInfo = GetType().GetMethod(nameof(OnHandlingEvent), BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)!; + var eventHandler = Delegate.CreateDelegate(eventInfo.EventHandlerType!, this, methodInfo); + + foreach (var target in targets) + { + eventInfo.AddEventHandler(target, eventHandler); + } + + _handlersMap.Add(eventInfo, eventHandler); + logger.LogDebug("Observing: {EventType}.{EventName}", eventInfo.ReflectedType, eventInfo.Name); + } + } + + private void Unsubscribe(UIApplication uiApplication) + { + foreach (var eventInfo in _handlersMap) + { + var targets = FindValidTargets(eventInfo.Key.ReflectedType); + foreach (var target in targets) + { + eventInfo.Key.RemoveEventHandler(target, eventInfo.Value); + } + } + + _handlersMap.Clear(); + } + + private static object[] FindValidTargets(Type? targetType) + { + if (targetType == typeof(Document)) return Context.Application.Documents.Cast().ToArray(); + if (targetType == typeof(Autodesk.Revit.ApplicationServices.Application)) return [Context.Application]; + if (targetType == typeof(UIApplication)) return [Context.UiApplication]; + + return []; + } + + public void OnHandlingEvent(object sender, EventArgs args) + { + var stackTrace = new StackTrace(); + var stackFrames = stackTrace.GetFrames()!; + var eventType = stackFrames[1].GetMethod()!.Name; + var eventName = eventType.Replace(nameof(EventHandler), ""); + + _callback?.Invoke(args, eventName); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Summary/VisualDecompositionService.cs b/source/RevitLookup/Services/Summary/VisualDecompositionService.cs new file mode 100644 index 000000000..10d7c047b --- /dev/null +++ b/source/RevitLookup/Services/Summary/VisualDecompositionService.cs @@ -0,0 +1,102 @@ +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using LookupEngine.Abstractions.Configuration; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.Core; +using RevitLookup.Core.Decomposition; +using OperationCanceledException = Autodesk.Revit.Exceptions.OperationCanceledException; +using Visibility = System.Windows.Visibility; + +namespace RevitLookup.Services.Summary; + +[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] +[SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] +public sealed class VisualDecompositionService( + IWindowIntercomService intercomService, + INotificationService notificationService, + IDecompositionService decompositionService, + IDecompositionSummaryViewModel summaryViewModel) + : IVisualDecompositionService +{ + public async Task VisualizeDecompositionAsync(KnownDecompositionObject decompositionObject) + { + try + { + switch (decompositionObject) + { + case KnownDecompositionObject.Face: + case KnownDecompositionObject.Edge: + case KnownDecompositionObject.LinkedElement: + case KnownDecompositionObject.Point: + case KnownDecompositionObject.SubElement: + HideHost(); + break; + } + + var objects = await RevitShell.AsyncCollectionHandler.RaiseAsync(_ => RevitObjectsCollector.GetObjects(decompositionObject)); + summaryViewModel.SelectedDecomposedObject = null; + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(objects); + } + catch (OperationCanceledException) + { + notificationService.ShowWarning("Operation cancelled", "Operation cancelled by user"); + } + catch (Exception exception) + { + notificationService.ShowError("Operation cancelled", exception); + } + finally + { + ShowHost(); + } + } + + private void ShowHost() + { + var host = intercomService.GetHost(); + if (!host.IsLoaded) return; + + host.Visibility = Visibility.Visible; + } + + private void HideHost() + { + var host = intercomService.GetHost(); + if (!host.IsLoaded) return; + + host.Visibility = Visibility.Hidden; + } + + public async Task VisualizeDecompositionAsync(object? obj) + { + var values = obj switch + { + ObservableDecomposedValue {Descriptor: IDescriptorEnumerator} decomposedValue => (IEnumerable) decomposedValue.RawValue!, + ObservableDecomposedValue decomposedValue => new[] {decomposedValue.RawValue}, + _ => new[] {obj} + }; + + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(values); + } + + public async Task VisualizeDecompositionAsync(IEnumerable objects) + { + summaryViewModel.DecomposedObjects = await decompositionService.DecomposeAsync(objects); + } + + public async Task VisualizeDecompositionAsync(ObservableDecomposedObject decomposedObject) + { + summaryViewModel.DecomposedObjects = [decomposedObject]; + await Task.CompletedTask; + } + + public async Task VisualizeDecompositionAsync(List decomposedObjects) + { + summaryViewModel.DecomposedObjects = decomposedObjects; + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/ViewModelServices.cs b/source/RevitLookup/Services/ViewModelServices.cs new file mode 100644 index 000000000..ae9ff69e9 --- /dev/null +++ b/source/RevitLookup/Services/ViewModelServices.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace RevitLookup.Services; + +public static class ViewModelServices +{ + public static void RegisterViewModels(this IServiceCollection services) + { + services.Scan(selector => selector.FromCallingAssembly() + .AddClasses(filter => filter.Where(type => type.Name.EndsWith("ViewModel"))) + .AsImplementedInterfaces(type => type.Name.EndsWith("ViewModel")) + .WithScopedLifetime()); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/ViewServices.cs b/source/RevitLookup/Services/ViewServices.cs new file mode 100644 index 000000000..92cf13699 --- /dev/null +++ b/source/RevitLookup/Services/ViewServices.cs @@ -0,0 +1,27 @@ +using System.Windows.Controls; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.UI.Framework; +using Wpf.Ui.Abstractions.Controls; +using Wpf.Ui.Controls; + +namespace RevitLookup.Services; + +public static class ViewServices +{ + public static void RegisterViews(this IServiceCollection services) + { + services.Scan(selector => selector.FromAssemblyOf() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithScopedLifetime() + .AddClasses(filter => filter.AssignableTo()).AsSelf().WithTransientLifetime() + .AddClasses(filter => + { + filter.AssignableTo(); + filter.Where(type => typeof(INavigableView).IsAssignableFrom(type)); + }).AsSelf().WithScopedLifetime() + .AddClasses(filter => + { + filter.AssignableTo(); + filter.Where(type => !typeof(INavigableView).IsAssignableFrom(type)); + }).AsSelf().WithTransientLifetime()); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Styles/App.Resources.xaml b/source/RevitLookup/Styles/App.Resources.xaml new file mode 100644 index 000000000..0a4d3666f --- /dev/null +++ b/source/RevitLookup/Styles/App.Resources.xaml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml new file mode 100644 index 000000000..6e702813c --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplate.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs new file mode 100644 index 000000000..a898b70d9 --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridCellTemplateSelector.cs @@ -0,0 +1,27 @@ +using System.Windows; +using System.Windows.Controls; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Styles.ComponentStyles.MembersGrid; + +/// +/// Data grid cell template selector +/// +public sealed class DataGridCellTemplateSelector : DataTemplateSelector +{ + public override DataTemplate? SelectTemplate(object? item, DependencyObject container) + { + if (item is null) return null; + + var member = (ObservableDecomposedMember) item; + var presenter = (FrameworkElement) container; + var templateName = member.Value.RawValue switch + { + Color => "SummaryMediaColorCellTemplate", + _ => "DefaultSummaryCellTemplate" + }; + + return (DataTemplate) presenter.FindResource(templateName); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml new file mode 100644 index 000000000..a4df8cf38 --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridGroupStyles.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml new file mode 100644 index 000000000..05f2361aa --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyle.xaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs new file mode 100644 index 000000000..c7ec6abd8 --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/MembersGrid/DataGridRowStyleSelector.cs @@ -0,0 +1,44 @@ +using System.Windows; +using System.Windows.Controls; +using LookupEngine.Abstractions.Configuration; +using LookupEngine.Abstractions.Decomposition; +using RevitLookup.Abstractions.ObservableModels.Decomposition; + +namespace RevitLookup.Styles.ComponentStyles.MembersGrid; + +/// +/// Data grid row style selector +/// +public sealed class DataGridRowStyleSelector : StyleSelector +{ + public override Style? SelectStyle(object item, DependencyObject container) + { + var member = (ObservableDecomposedMember) item; + var presenter = (FrameworkElement) container; + + var styleName = SelectByType(member.Value.RawValue) ?? + SelectByDescriptor(member.Value.Descriptor); + + return (Style) presenter.FindResource(styleName); + } + + private static string? SelectByType(object? value) + { + return value switch + { + Exception => "ExceptionDataGridRowStyle", + _ => null + }; + } + + private static string SelectByDescriptor(Descriptor? descriptor) + { + return descriptor switch + { + IDescriptorEnumerator {IsEmpty: false} => "HandledDataGridRowStyle", + IDescriptorEnumerator => "DefaultLookupDataGridRowStyle", + IDescriptorCollector => "HandledDataGridRowStyle", + _ => "DefaultLookupDataGridRowStyle" + }; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml b/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml new file mode 100644 index 000000000..12689f5b6 --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeGroupTemplates.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs b/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs new file mode 100644 index 000000000..8dec869fe --- /dev/null +++ b/source/RevitLookup/Styles/ComponentStyles/ObjectsTree/TreeViewItemTemplateSelector.cs @@ -0,0 +1,27 @@ +using System.Windows; +using System.Windows.Controls; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Styles.ComponentStyles.ObjectsTree; + +public sealed class TreeViewItemTemplateSelector : DataTemplateSelector +{ + /// + /// Tree view row style selector + /// + public override DataTemplate? SelectTemplate(object? item, DependencyObject container) + { + if (item is null) return null; + + var presenter = (FrameworkElement) container; + var decomposedObject = (ObservableDecomposedObject) item; + var templateName = decomposedObject.RawValue switch + { + Color => "SummaryMediaColorItemTemplate", + _ => "DefaultSummaryTreeItemTemplate" + }; + + return (DataTemplate) presenter.FindResource(templateName); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Styles/Converters/ObjectColorConverter.cs b/source/RevitLookup/Styles/Converters/ObjectColorConverter.cs new file mode 100644 index 000000000..14eaab160 --- /dev/null +++ b/source/RevitLookup/Styles/Converters/ObjectColorConverter.cs @@ -0,0 +1,28 @@ +using System.Globalization; +using System.Windows.Data; +using System.Windows.Markup; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.Styles.Converters; + +public sealed class ObjectColorConverter : MarkupExtension, IValueConverter +{ + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return value switch + { + Color color => color, + _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) + }; + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + return this; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Utils/Media/RevitColorFormatUtils.cs b/source/RevitLookup/Utils/Media/RevitColorFormatUtils.cs new file mode 100644 index 000000000..1d7b092f1 --- /dev/null +++ b/source/RevitLookup/Utils/Media/RevitColorFormatUtils.cs @@ -0,0 +1,37 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Color = System.Drawing.Color; + +namespace RevitLookup.Utils.Media; + +/// +/// Helper class to easier work with color formats +/// +public static class RevitColorFormatUtils +{ + /// + /// Return a drawing color of a given + /// + public static Color GetDrawingColor(this Autodesk.Revit.DB.Color color) + { + return Color.FromArgb(1, color.Red, color.Green, color.Blue); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/AboutProgram/AboutViewModel.cs b/source/RevitLookup/ViewModels/AboutProgram/AboutViewModel.cs new file mode 100644 index 000000000..c78e04ed6 --- /dev/null +++ b/source/RevitLookup/ViewModels/AboutProgram/AboutViewModel.cs @@ -0,0 +1,143 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Net.Http; +using System.Runtime; +using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using RevitLookup.Abstractions.Options; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.States; +using RevitLookup.Abstractions.ViewModels.AboutProgram; +using RevitLookup.UI.Framework.Views.AboutProgram; + +namespace RevitLookup.ViewModels.AboutProgram; + +[UsedImplicitly] +public sealed partial class AboutViewModel : ObservableObject, IAboutViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly ISoftwareUpdateService _updateService; + private readonly ILogger _logger; + + [ObservableProperty] private SoftwareUpdateState _state = (SoftwareUpdateState) (-1); + [ObservableProperty] private Version? _currentVersion; + [ObservableProperty] private string? _newVersion; + [ObservableProperty] private string? _releaseNotesUrl; + [ObservableProperty] private string? _latestCheckDate; + [ObservableProperty] private string? _errorMessage; + [ObservableProperty] private string? _runtime; + + public AboutViewModel( + IServiceProvider serviceProvider, + ISoftwareUpdateService updateService, + IOptions assemblyOptions, + ILogger logger) + { + _serviceProvider = serviceProvider; + _updateService = updateService; + _logger = logger; + + CurrentVersion = assemblyOptions.Value.Version; + Runtime = new StringBuilder() + .Append(assemblyOptions.Value.Framework) + .Append(' ') + .Append(Environment.Is64BitProcess ? "x64" : "x86") + .Append(" (") + .Append(GCSettings.IsServerGC ? "Server" : "Workstation") + .Append(" GC)") + .ToString(); + + LatestCheckDate = _updateService.LatestCheckDate?.ToString("yyyy.MM.dd HH:mm:ss"); + UpdateSoftwareState(); + } + + [RelayCommand] + private async Task CheckUpdatesAsync() + { + try + { + var result = await _updateService.CheckUpdatesAsync(); + + if (!result) + { + State = SoftwareUpdateState.UpToDate; + return; + } + + UpdateSoftwareState(); + } + catch (HttpRequestException exception) + { + State = SoftwareUpdateState.UpToDate; + _logger.LogError(exception, "Checking updates fail"); + } + catch (Exception exception) + { + State = SoftwareUpdateState.Error; + ErrorMessage = "An unknown error occurred while checking for updates"; + _logger.LogError(exception, "Checking updates fail"); + } + finally + { + LatestCheckDate = _updateService.LatestCheckDate?.ToString("yyyy.MM.dd HH:mm:ss"); + } + } + + [RelayCommand] + private async Task DownloadUpdateAsync() + { + try + { + await _updateService.DownloadUpdate(); + State = SoftwareUpdateState.ReadyToInstall; + } + catch (Exception exception) + { + State = SoftwareUpdateState.Error; + ErrorMessage = "An error occurred while downloading the update"; + _logger.LogError(exception, "Downloading updates fail"); + } + } + + [RelayCommand] + private async Task ShowSoftwareDialogAsync() + { + var dialog = _serviceProvider.GetRequiredService(); + await dialog.ShowAsync(); + } + + private void UpdateSoftwareState() + { + if (_updateService.LocalFilePath is not null) + { + State = SoftwareUpdateState.ReadyToInstall; + return; + } + + if (_updateService.NewVersion is null) return; + + NewVersion = _updateService.NewVersion; + ReleaseNotesUrl = _updateService.ReleaseNotesUrl; + State = SoftwareUpdateState.ReadyToDownload; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/AboutProgram/OpenSourceViewModel.cs b/source/RevitLookup/ViewModels/AboutProgram/OpenSourceViewModel.cs new file mode 100644 index 000000000..3fbff6fe2 --- /dev/null +++ b/source/RevitLookup/ViewModels/AboutProgram/OpenSourceViewModel.cs @@ -0,0 +1,95 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using RevitLookup.Abstractions.Models.AboutProgram; +using RevitLookup.Abstractions.ViewModels.AboutProgram; + +namespace RevitLookup.ViewModels.AboutProgram; + +[UsedImplicitly] +public sealed class OpenSourceViewModel : ObservableObject, IOpenSourceViewModel +{ + public List Software { get; } = + [ + new() + { + SoftwareName = "CommunityToolkit.Mvvm", + SoftwareUri = "https://github.com/CommunityToolkit/dotnet", + LicenseName = "MIT License", + LicenseUri = "https://github.com/CommunityToolkit/dotnet/blob/main/License.md" + }, + new() + { + SoftwareName = "Microsoft.Extensions.Hosting", + SoftwareUri = "https://github.com/dotnet/runtime", + LicenseName = "MIT License", + LicenseUri = "https://github.com/dotnet/runtime/blob/main/LICENSE.TXT" + }, + new() + { + SoftwareName = "Nice3point.Revit.Api", + SoftwareUri = "https://github.com/Nice3point/RevitApi", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitApi/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Extensions", + SoftwareUri = "https://github.com/Nice3point/RevitExtensions", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitExtensions/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Templates", + SoftwareUri = "https://github.com/Nice3point/RevitTemplates", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitTemplates/blob/main/License.md" + }, + new() + { + SoftwareName = "Nice3point.Revit.Toolkit", + SoftwareUri = "https://github.com/Nice3point/RevitToolkit", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Nice3point/RevitToolkit/blob/main/License.md" + }, + new() + { + SoftwareName = "PolySharp", + SoftwareUri = "https://github.com/Sergio0694/PolySharp", + LicenseName = "MIT License", + LicenseUri = "https://github.com/Sergio0694/PolySharp/blob/main/LICENSE" + }, + new() + { + SoftwareName = "Serilog", + SoftwareUri = "https://github.com/serilog/serilog", + LicenseName = "Apache License 2.0", + LicenseUri = "https://github.com/serilog/serilog/blob/dev/LICENSE" + }, + new() + { + SoftwareName = "WPF-UI", + SoftwareUri = "https://github.com/lepoco/wpfui", + LicenseName = "MIT License", + LicenseUri = "https://github.com/lepoco/wpfui/blob/main/LICENSE" + } + ]; +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Dashboard/DashboardViewModel.cs b/source/RevitLookup/ViewModels/Dashboard/DashboardViewModel.cs new file mode 100644 index 000000000..b612517e2 --- /dev/null +++ b/source/RevitLookup/ViewModels/Dashboard/DashboardViewModel.cs @@ -0,0 +1,425 @@ +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Models.Decomposition; +using RevitLookup.Abstractions.Models.UserInterface; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Dashboard; +using RevitLookup.UI.Framework.Views.Decomposition; +using RevitLookup.UI.Framework.Views.Tools; +using Wpf.Ui; +using Wpf.Ui.Controls; +using ArgumentOutOfRangeException = System.ArgumentOutOfRangeException; + +namespace RevitLookup.ViewModels.Dashboard; + +[UsedImplicitly] +public sealed partial class DashboardViewModel : IDashboardViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly INavigationService _navigationService; + private readonly INotificationService _notificationService; + private readonly IVisualDecompositionService _visualDecompositionService; + + public DashboardViewModel( + IServiceProvider serviceProvider, + INavigationService navigationService, + INotificationService notificationService, + IVisualDecompositionService visualDecompositionService) + { + _serviceProvider = serviceProvider; + _navigationService = navigationService; + _notificationService = notificationService; + _visualDecompositionService = visualDecompositionService; + + NavigationGroups = + [ + new NavigationCardGroup + { + GroupName = "Workspace", + Items = + [ + new NavigationCardItem + { + Title = "Active view", + Description = "Explore and analyze the model's visual representation", + Icon = SymbolRegular.Image24, + Command = NavigatePageCommand, + CommandParameter = "view" + }, + new NavigationCardItem + { + Title = "Active document", + Description = "Explore the open document, including its structure and data", + Icon = SymbolRegular.Document24, + Command = NavigatePageCommand, + CommandParameter = "document" + }, + new NavigationCardItem + { + Title = "Application", + Description = "Explore application-wide settings and global data", + Icon = SymbolRegular.Apps24, + Command = NavigatePageCommand, + CommandParameter = "application" + }, + new NavigationCardItem + { + Title = "UI application", + Description = "Explore an active session of the Revit user interface", + Icon = SymbolRegular.WindowApps24, + Command = NavigatePageCommand, + CommandParameter = "uiApplication" + }, + new NavigationCardItem + { + Title = "UI controlled application", + Description = "Explore the Revit UI customization methods and events", + Icon = SymbolRegular.SquareHintApps24, + Command = NavigatePageCommand, + CommandParameter = "uiControlledApplication" + }, + new NavigationCardItem + { + Title = "Database", + Description = "Explore the Revit model database and its elements", + Icon = SymbolRegular.Database24, + Command = NavigatePageCommand, + CommandParameter = "database" + }, + ] + }, + new NavigationCardGroup + { + GroupName = "Interaction", + Items = + [ + new NavigationCardItem + { + Title = "Selection", + Description = "Explore currently selected elements in the model", + Icon = SymbolRegular.SquareHint24, + Command = NavigatePageCommand, + CommandParameter = "selection" + }, + new NavigationCardItem + { + Title = "Linked element", + Description = "Select and explore an element linked from another model", + Icon = SymbolRegular.LinkSquare24, + Command = NavigatePageCommand, + CommandParameter = "linked" + }, + new NavigationCardItem + { + Title = "Face", + Description = "Select and explore a face of the element's geometry", + Icon = SymbolRegular.LayerDiagonal20, + Command = NavigatePageCommand, + CommandParameter = "face" + }, + new NavigationCardItem + { + Title = "Edge", + Description = "Select and explore the edge of the element's geometry", + Icon = SymbolRegular.Line24, + Command = NavigatePageCommand, + CommandParameter = "edge" + }, + new NavigationCardItem + { + Title = "Point", + Description = "Select and explore a specific location or coordinate", + Icon = SymbolRegular.Location24, + Command = NavigatePageCommand, + CommandParameter = "point" + }, + new NavigationCardItem + { + Title = "Sub-element", + Description = "Select and explore a sub-element of the selected element", + Icon = SymbolRegular.Subtitles24, + Command = NavigatePageCommand, + CommandParameter = "subElement" + }, + new NavigationCardItem + { + Title = "Dependent elements", + Description = "Explore child elements associated with the selection", + Icon = SymbolRegular.DataLine24, + Command = NavigatePageCommand, + CommandParameter = "dependents" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Maintenance", + Items = + [ + new NavigationCardItem + { + Title = "Component manager", + Description = "Explore low-level visual components in Revit", + Icon = SymbolRegular.SlideTextMultiple32, + Command = NavigatePageCommand, + CommandParameter = "components" + }, + new NavigationCardItem + { + Title = "Performance adviser", + Description = "Explore performance issues in the open document", + Icon = SymbolRegular.HeartPulse24, + Command = NavigatePageCommand, + CommandParameter = "performance" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Registry", + Items = + [ + new NavigationCardItem + { + Title = "Updaters", + Description = "Explore all registered updaters in the session", + Icon = SymbolRegular.Whiteboard24, + Command = NavigatePageCommand, + CommandParameter = "updaters" + }, + new NavigationCardItem + { + Title = "Schemas", + Description = "Explore Extensible Storage framework schemas", + Icon = SymbolRegular.Box24, + Command = NavigatePageCommand, + CommandParameter = "schemas" + }, + new NavigationCardItem + { + Title = "Services", + Description = "Explore services that extend Revit's functionality", + Icon = SymbolRegular.WeatherCloudy24, + Command = NavigatePageCommand, + CommandParameter = "services" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Units", + Items = + [ + new NavigationCardItem + { + Title = "BuiltIn parameters", + Description = "Explore predefined parameters available in Revit", + Icon = SymbolRegular.LeafOne24, + Command = OpenDialogCommand, + CommandParameter = "parameters" + }, + new NavigationCardItem + { + Title = "BuiltIn categories", + Description = "Explore predefined categories available in Revit", + Icon = SymbolRegular.LeafTwo24, + Command = OpenDialogCommand, + CommandParameter = "categories" + }, + new NavigationCardItem + { + Title = "Forge schema", + Description = "Explore Forge schema definitions used in Revit", + Icon = SymbolRegular.LeafThree24, + Command = OpenDialogCommand, + CommandParameter = "forge" + } + ] + }, + new NavigationCardGroup + { + GroupName = "Tools", + Items = + [ + new NavigationCardItem + { + Title = "Search elements", + Description = "Search for specific elements in the model", + Icon = SymbolRegular.SlideSearch24, + Command = OpenDialogCommand, + CommandParameter = "search" + }, + new NavigationCardItem + { + Title = "Event monitor", + Description = "Monitor all incoming events in a Revit session", + Icon = SymbolRegular.DesktopPulse24, + Command = NavigatePageCommand, + CommandParameter = "events" + }, + new NavigationCardItem + { + Title = "Revit settings", + Description = "Inspect configuration and Revit settings available in the application", + Icon = SymbolRegular.LauncherSettings24, + Command = NavigatePageCommand, + CommandParameter = "revitSettings" + }, + new NavigationCardItem + { + Title = "Modules", + Description = "Inspect the dynamic link libraries (DLLs) that Revit uses", + Icon = SymbolRegular.BroadActivityFeed24, + Command = OpenDialogCommand, + CommandParameter = "modules" + } + ] + } + ]; + } + + public List NavigationGroups { get; } + + [RelayCommand] + private async Task NavigatePage(string? parameter) + { + if (!ValidateContext()) return; + + try + { + switch (parameter) + { + case "view": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.View); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "document": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Document); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "application": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Application); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "uiApplication": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UiApplication); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "uiControlledApplication": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UiControlledApplication); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "database": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Database); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "dependents": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.DependentElements); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "selection": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Selection); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "linked": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.LinkedElement); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "face": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Face); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "edge": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Edge); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "point": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Point); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "subElement": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.SubElement); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "components": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.ComponentManager); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "performance": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.PerformanceAdviser); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "updaters": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.UpdaterRegistry); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "services": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Services); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "schemas": + await _visualDecompositionService.VisualizeDecompositionAsync(KnownDecompositionObject.Schemas); + _navigationService.Navigate(typeof(DecompositionSummaryPage)); + break; + case "events": + _navigationService.Navigate(typeof(EventsSummaryPage)); + break; + case "revitSettings": + _navigationService.NavigateWithHierarchy(typeof(RevitSettingsPage)); + break; + default: + throw new ArgumentOutOfRangeException(nameof(parameter), parameter); + } + } + catch (Exception exception) + { + _notificationService.ShowError("Failed to run tool", exception); + } + } + + [RelayCommand] + private async Task OpenDialog(string parameter) + { + try + { + if (!ValidateContext()) return; + + switch (parameter) + { + case "parameters": + var unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowParametersDialogAsync(); + return; + case "categories": + unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowCategoriesDialogAsync(); + return; + case "forge": + unitsDialog = _serviceProvider.GetRequiredService(); + await unitsDialog.ShowForgeSchemaDialogAsync(); + return; + case "search": + var searchDialog = _serviceProvider.GetRequiredService(); + await searchDialog.ShowAsync(); + return; + case "modules": + var modulesDialog = _serviceProvider.GetRequiredService(); + await modulesDialog.ShowAsync(); + return; + } + } + catch (Exception exception) + { + _notificationService.ShowError("Failed to open dialog", exception); + } + } + + //TODO: allow context independent commands + private bool ValidateContext() + { + if (Context.ActiveUiDocument is not null) return true; + + _notificationService.ShowWarning("Invalid context", "There are no open documents"); + return false; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Decomposition/DecompositionSummaryViewModel.cs b/source/RevitLookup/ViewModels/Decomposition/DecompositionSummaryViewModel.cs new file mode 100644 index 000000000..367bbca72 --- /dev/null +++ b/source/RevitLookup/ViewModels/Decomposition/DecompositionSummaryViewModel.cs @@ -0,0 +1,178 @@ +using System.Collections.ObjectModel; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Decomposition; + +namespace RevitLookup.ViewModels.Decomposition; + +[UsedImplicitly] +public sealed partial class DecompositionSummaryViewModel( + IWindowIntercomService intercomService, + IDecompositionService decompositionService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IDecompositionSummaryViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private ObservableDecomposedObject? _selectedDecomposedObject; + [ObservableProperty] private List _decomposedObjects = []; + [ObservableProperty] private ObservableCollection _filteredDecomposedObjects = []; + + public void Navigate(object? value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(ObservableDecomposedObject value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(List values) + { + Host.GetService() + .Decompose(values) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public async Task RefreshMembersAsync() + { + foreach (var decomposedObject in DecomposedObjects) + { + decomposedObject.Members.Clear(); + } + + try + { + await FetchMembersAsync(SelectedDecomposedObject); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + public void RemoveItem(object target) + { + switch (target) + { + case ObservableDecomposedObject decomposedObject: + for (var i = FilteredDecomposedObjects.Count - 1; i >= 0; i--) + { + var groupToRemove = FilteredDecomposedObjects[i]; + if (!groupToRemove.GroupItems.Remove(decomposedObject)) continue; + + if (groupToRemove.GroupItems.Count == 0) + { + //Remove the empty group + FilteredDecomposedObjects.Remove(groupToRemove); + } + } + + if (DecomposedObjects.Remove(decomposedObject)) + { + if (DecomposedObjects.Count == 0) + { + //Notify UI to update placeholders + OnPropertyChanged(nameof(DecomposedObjects)); + } + } + + break; + case ObservableDecomposedMember: + //Do nothing ?? + break; + } + } + + partial void OnDecomposedObjectsChanged(List value) + { + OnSearchTextChanged(SearchText); + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredDecomposedObjects = ApplyGrouping(DecomposedObjects); + return; + } + + FilteredDecomposedObjects = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var item in DecomposedObjects) + { + if (item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(item); + } + } + + return ApplyGrouping(searchResults); + }); + + if (FilteredDecomposedObjects.Count == 0) + { + SelectedDecomposedObject = null; + } + } + catch + { + // ignored + } + } + + async partial void OnSelectedDecomposedObjectChanged(ObservableDecomposedObject? value) + { + try + { + await FetchMembersAsync(value); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + private async Task FetchMembersAsync(ObservableDecomposedObject? value) + { + if (value is null) return; + if (value.Members.Count > 0) return; + + value.Members = await decompositionService.DecomposeMembersAsync(value); + } + + [Pure] + private ObservableCollection ApplyGrouping(List objects) + { + return objects + .OrderBy(data => data.TypeName) + .ThenBy(data => data.Name) + .GroupBy(data => data.TypeName) + .Select(group => new ObservableDecomposedObjectsGroup + { + GroupName = group.Key, + GroupItems = group.ToObservableCollection() + }) + .ToObservableCollection(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Decomposition/EventsSummaryViewModel.cs b/source/RevitLookup/ViewModels/Decomposition/EventsSummaryViewModel.cs new file mode 100644 index 000000000..d109b931b --- /dev/null +++ b/source/RevitLookup/ViewModels/Decomposition/EventsSummaryViewModel.cs @@ -0,0 +1,182 @@ +using System.Collections.ObjectModel; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Decomposition; +using RevitLookup.Abstractions.Services.Application; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Decomposition; +using RevitLookup.Services.Summary; +using RevitLookup.UI.Framework.Extensions; +using RevitLookup.UI.Framework.Views.Decomposition; + +namespace RevitLookup.ViewModels.Decomposition; + +[UsedImplicitly] +public sealed partial class EventsSummaryViewModel( + IWindowIntercomService intercomService, + INotificationService notificationService, + IDecompositionService decompositionService, + EventsMonitoringService monitoringService, + ILogger logger) + : ObservableObject, IEventsSummaryViewModel +{ + private readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current!; + + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private ObservableDecomposedObject? _selectedDecomposedObject; + [ObservableProperty] private List _decomposedObjects = []; + [ObservableProperty] private ObservableCollection _filteredDecomposedObjects = []; + + public void Navigate(object? value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(ObservableDecomposedObject value) + { + Host.GetService() + .Decompose(value) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public void Navigate(List values) + { + Host.GetService() + .Decompose(values) + .DependsOn(intercomService.GetHost()) + .Show(); + } + + public async Task RefreshMembersAsync() + { + foreach (var decomposedObject in DecomposedObjects) + { + decomposedObject.Members.Clear(); + } + + try + { + await FetchMembersAsync(SelectedDecomposedObject); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + public Task OnNavigatedToAsync() + { + monitoringService.RegisterEventInvocationCallback(OnEventInvoked); + return Task.CompletedTask; + } + + public Task OnNavigatedFromAsync() + { + monitoringService.Unregister(); + return Task.CompletedTask; + } + + partial void OnDecomposedObjectsChanged(List value) + { + OnSearchTextChanged(SearchText); + } + + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredDecomposedObjects = DecomposedObjects.ToObservableCollection(); + return; + } + + FilteredDecomposedObjects = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var item in DecomposedObjects) + { + if (IsSearchValueMatching(item, formattedText)) + { + searchResults.Add(item); + } + } + + return searchResults.ToObservableCollection(); + }); + + if (FilteredDecomposedObjects.Count == 0) + { + SelectedDecomposedObject = null; + } + } + catch + { + // ignored + } + } + + private bool IsSearchValueMatching(ObservableDecomposedObject item, string formattedText) + { + return item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + item.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase); + } + + async partial void OnSelectedDecomposedObjectChanged(ObservableDecomposedObject? value) + { + try + { + await FetchMembersAsync(value); + } + catch (Exception exception) + { + logger.LogError(exception, "Members decomposing failed"); + notificationService.ShowError("Lookup engine error", exception); + } + } + + private async void OnEventInvoked(object value, string eventName) + { + try + { + var decomposedObject = await decompositionService.DecomposeAsync(value); + + _synchronizationContext.Post(state => + { + var viewModel = (EventsSummaryViewModel) state!; + + decomposedObject.Name = $"{eventName} {DateTime.Now:HH:mm:ss}"; + viewModel.DecomposedObjects.Insert(0, decomposedObject); + + if (viewModel.IsSearchValueMatching(decomposedObject, viewModel.SearchText)) + { + viewModel.FilteredDecomposedObjects.Insert(0, decomposedObject); + } + else + { + viewModel.OnSearchTextChanged(viewModel.SearchText); + } + }, this); + } + catch (Exception exception) + { + logger.LogError(exception, "Events data parsing error"); + notificationService.ShowError("Events data parsing error", exception); + } + } + + private async Task FetchMembersAsync(ObservableDecomposedObject? decomposedObject) + { + if (decomposedObject is null) return; + if (decomposedObject.Members.Count > 0) return; + + decomposedObject.Members = await decompositionService.DecomposeMembersAsync(decomposedObject); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Settings/SettingsViewModel.cs b/source/RevitLookup/ViewModels/Settings/SettingsViewModel.cs new file mode 100644 index 000000000..c40b03bc7 --- /dev/null +++ b/source/RevitLookup/ViewModels/Settings/SettingsViewModel.cs @@ -0,0 +1,210 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics; +using Microsoft.Extensions.DependencyInjection; +using RevitLookup.Abstractions.Services.Appearance; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Settings; +using RevitLookup.Services.Application; +using RevitLookup.UI.Framework.Views.Settings; +using RevitLookup.UI.Framework.Views.Windows; +using Wpf.Ui; +using Wpf.Ui.Animations; +using Wpf.Ui.Appearance; +using Wpf.Ui.Controls; +using ApplicationTheme = Wpf.Ui.Appearance.ApplicationTheme; + +namespace RevitLookup.ViewModels.Settings; + +[UsedImplicitly] +public sealed partial class SettingsViewModel : ObservableObject, ISettingsViewModel +{ + private readonly IServiceProvider _serviceProvider; + private readonly INavigationService _navigationService; + private readonly INotificationService _notificationService; + private readonly ISettingsService _settingsService; + private readonly IWindowIntercomService _intercomService; + private readonly IThemeWatcherService _themeWatcherService; + private readonly RevitRibbonService _ribbonService; + private readonly bool _initialized; + + [ObservableProperty] private ApplicationTheme _theme; + [ObservableProperty] private WindowBackdropType _background; + + [ObservableProperty] private bool _useTransition; + [ObservableProperty] private bool _useHardwareRendering; + [ObservableProperty] private bool _useSizeRestoring; + [ObservableProperty] private bool _useModifyTab; + + public SettingsViewModel( + IServiceProvider serviceProvider, + INavigationService navigationService, + INotificationService notificationService, + ISettingsService settingsService, + IWindowIntercomService intercomService, + IThemeWatcherService themeWatcherService, + RevitRibbonService ribbonService) + { + _serviceProvider = serviceProvider; + _navigationService = navigationService; + _notificationService = notificationService; + _settingsService = settingsService; + _intercomService = intercomService; + _themeWatcherService = themeWatcherService; + _ribbonService = ribbonService; + + ApplySettings(); + _initialized = true; + } + + public List Themes { get; } = + [ + ApplicationTheme.Auto, + ApplicationTheme.Light, + ApplicationTheme.Dark + // ApplicationTheme.HighContrast + ]; + + public List BackgroundEffects { get; } = + [ + WindowBackdropType.None, + WindowBackdropType.Acrylic, + WindowBackdropType.Tabbed, + WindowBackdropType.Mica + ]; + + [RelayCommand] + private async Task ResetSettings() + { + try + { + var dialog = _serviceProvider.GetRequiredService(); + var result = await dialog.ShowAsync(); + if (result != ContentDialogResult.Primary) return; + + if (dialog.CanResetGeneralSettings) + { + _settingsService.ResetGeneralSettings(); + } + + if (dialog.CanResetRenderSettings) + { + _settingsService.ResetRenderSettings(); + } + + ApplySettings(); + + _notificationService.ShowSuccess("Reset settings", "Settings successfully reset to default"); + } + catch (Exception exception) + { + _notificationService.ShowError("Reset settings error", exception); + } + } + + partial void OnThemeChanged(ApplicationTheme value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.Theme = value; + _themeWatcherService.Watch(); + } + + partial void OnThemeChanged(ApplicationTheme oldValue, ApplicationTheme newValue) + { + if (!_initialized) return; + + if (oldValue == ApplicationTheme.Auto) + { + _themeWatcherService.Unwatch(); + } + } + + partial void OnBackgroundChanged(WindowBackdropType value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.Background = value; + WindowBackgroundManager.UpdateBackground(_intercomService.GetHost(), _settingsService.GeneralSettings.Theme, value); + } + + partial void OnUseTransitionChanged(bool value) + { + if (!_initialized) return; + + var navigationControl = _navigationService.GetNavigationControl(); + var transition = _settingsService.GeneralSettings.Transition = value + ? (Transition) NavigationView.TransitionProperty.DefaultMetadata.DefaultValue + : Transition.None; + + _settingsService.GeneralSettings.Transition = transition; + navigationControl.Transition = transition; + } + + partial void OnUseHardwareRenderingChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseHardwareRendering = value; + if (value) Application.EnableHardwareRendering(); + else Application.DisableHardwareRendering(); + } + + partial void OnUseSizeRestoringChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseSizeRestoring = value; + if (_intercomService.GetHost() is not RevitLookupView lookupView) + { + Debug.Fail("Settings page running inside invalid host"); + return; + } + + if (value) + { + lookupView.EnableSizeTracking(); + } + else + { + lookupView.DisableSizeTracking(); + } + } + + partial void OnUseModifyTabChanged(bool value) + { + if (!_initialized) return; + + _settingsService.GeneralSettings.UseModifyTab = value; + _ribbonService.CreateRibbon(); + } + + private void ApplySettings() + { + Theme = _settingsService.GeneralSettings.Theme; + Background = _settingsService.GeneralSettings.Background; + UseTransition = _settingsService.GeneralSettings.Transition != Transition.None; + UseHardwareRendering = _settingsService.GeneralSettings.UseHardwareRendering; + UseSizeRestoring = _settingsService.GeneralSettings.UseSizeRestoring; + UseModifyTab = _settingsService.GeneralSettings.UseModifyTab; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Tools/ModulesViewModel.cs b/source/RevitLookup/ViewModels/Tools/ModulesViewModel.cs new file mode 100644 index 000000000..ff6a12c0a --- /dev/null +++ b/source/RevitLookup/ViewModels/Tools/ModulesViewModel.cs @@ -0,0 +1,103 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + + +using System.Diagnostics.CodeAnalysis; +using RevitLookup.Abstractions.Models.Tools; +using RevitLookup.Abstractions.ViewModels.Tools; +#if NETCOREAPP +using System.Runtime.Loader; +#endif + +namespace RevitLookup.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class ModulesViewModel : ObservableObject, IModulesViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + [ObservableProperty] private List _modules = []; + [ObservableProperty] private List _filteredModules = []; + + public ModulesViewModel() + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + Modules = new List(assemblies.Length); + + for (var i = 0; i < assemblies.Length; i++) + { + var assembly = assemblies[i]; + var assemblyName = assembly.GetName(); + var module = new ModuleInfo + { + Name = assemblyName.Name ?? string.Empty, + Path = assembly.IsDynamic ? string.Empty : assembly.Location, + Order = i + 1, + Version = assemblyName.Version is null ? string.Empty : assemblyName.Version.ToString(), +#if NETCOREAPP + Container = AssemblyLoadContext.GetLoadContext(assembly)?.Name ?? string.Empty +#else + Container = AppDomain.CurrentDomain.FriendlyName +#endif + }; + + Modules.Add(module); + } + } + + [SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredModules = Modules; + return; + } + + FilteredModules = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var module in Modules) + { + if (module.Name.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + module.Path.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + module.Version.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(module); + } + } + + return searchResults; + }); + } + catch + { + // ignored + } + } + + partial void OnModulesChanged(List value) + { + FilteredModules = value; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Tools/RevitSettingsViewModel.cs b/source/RevitLookup/ViewModels/Tools/RevitSettingsViewModel.cs new file mode 100644 index 000000000..069d4871f --- /dev/null +++ b/source/RevitLookup/ViewModels/Tools/RevitSettingsViewModel.cs @@ -0,0 +1,261 @@ +using System.Collections.ObjectModel; +using System.IO; +using System.Linq.Expressions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.ObservableModels.Entries; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Tools; +using RevitLookup.Common.Tools; +using RevitLookup.Core.Tools.RevitSettings; +using RevitLookup.UI.Framework.Views.EditDialogs; +using Wpf.Ui.Controls; + +namespace RevitLookup.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class RevitSettingsViewModel( + IServiceProvider serviceProvider, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IRevitSettingsViewModel +{ + private readonly RevitConfigurator _configurator = new(); + private TaskNotifier>? _initializationTask; + + [ObservableProperty] [NotifyCanExecuteChangedFor(nameof(ClearFiltersCommand))] private bool _filtered; + [ObservableProperty] private string _categoryFilter = string.Empty; + [ObservableProperty] private string _propertyFilter = string.Empty; + [ObservableProperty] private string _valueFilter = string.Empty; + [ObservableProperty] private bool _showUserSettingsFilter; + [ObservableProperty] private ObservableIniEntry? _selectedEntry; + + [ObservableProperty] private List _entries = []; + [ObservableProperty] private ObservableCollection _filteredEntries = []; + + public Task>? InitializationTask + { + get => _initializationTask!; + private set => SetPropertyAndNotifyOnCompletion(ref _initializationTask, value); + } + + public async Task InitializeAsync() + { + try + { + InitializationTask = _configurator.ReadAsync(); + Entries = await InitializationTask; + } + catch (Exception exception) + { + const string message = "Unavailable to parse Revit configuration"; + + logger.LogError(exception, message); + notificationService.ShowError(message, exception); + } + } + + [RelayCommand] + private async Task CreateEntry() + { + try + { + var dialog = serviceProvider.GetRequiredService(); + var result = await dialog.ShowCreateDialogAsync(SelectedEntry); + if (result == ContentDialogResult.Primary) + { + if (dialog.Entry.Category.IsNullOrWhiteSpace()) return; + if (dialog.Entry.Property.IsNullOrWhiteSpace()) return; + + Entries.Add(dialog.Entry); + FilteredEntries.Add(dialog.Entry); + _ = Task.Run(SaveAsync); + } + } + catch (Exception exception) + { + const string message = "Failed to create a new entry"; + + logger.LogError(exception, message); + notificationService.ShowError(message, exception); + } + } + + [RelayCommand] + private void ActivateEntry(ObservableIniEntry entry) + { + Task.Run(SaveAsync); + } + + [RelayCommand] + private void DeleteEntry(ObservableIniEntry entry) + { + Entries.Remove(entry); + FilteredEntries.Remove(entry); + Task.Run(SaveAsync); + } + + [RelayCommand] + private void RestoreDefault(ObservableIniEntry entry) + { + entry.Value = entry.DefaultValue ?? string.Empty; + Task.Run(SaveAsync); + } + + [RelayCommand] + private void ShowHelp() + { + var version = Context.Application.VersionNumber; + ProcessTasks.StartShell($"https://help.autodesk.com/view/RVT/{version}/ENU/?guid=GUID-9ECD669E-81D3-43E5-9970-9FA1C38E8507"); + } + + [RelayCommand] + private void OpenSettings() + { + var iniFile = Context.Application.CurrentUsersDataFolderPath.AppendPath("Revit.ini"); + if (!File.Exists(iniFile)) + { + notificationService.ShowWarning("Missing settings", "Revit.ini file does not exists"); + return; + } + + ProcessTasks.StartShell(iniFile); + } + + [RelayCommand(CanExecute = nameof(CanClearFiltersExecute))] + private void ClearFilters() + { + CategoryFilter = string.Empty; + PropertyFilter = string.Empty; + ValueFilter = string.Empty; + ShowUserSettingsFilter = false; + + ApplyFilters(); + } + + partial void OnEntriesChanged(List value) + { + ApplyFilters(); + } + + partial void OnCategoryFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnPropertyFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnValueFilterChanged(string value) + { + ApplyFilters(); + } + + partial void OnShowUserSettingsFilterChanged(bool value) + { + ApplyFilters(); + } + + public async Task UpdateEntryAsync() + { + if (SelectedEntry is null) return; + + try + { + var editingValue = SelectedEntry.Clone(); + var dialog = serviceProvider.GetRequiredService(); + var result = await dialog.ShowUpdateDialogAsync(editingValue); + if (result == ContentDialogResult.Primary) UpdateEntry(editingValue); + } + catch (Exception exception) + { + const string message = "Unavailable to update Revit configuration"; + + logger.LogError(exception, message); + notificationService.ShowError(message, exception); + } + } + + private void UpdateEntry(ObservableIniEntry entry) + { + if (SelectedEntry is null) return; + + var forceRefresh = SelectedEntry.Category != entry.Category || SelectedEntry.Property != entry.Property; + + SelectedEntry.Category = entry.Category; + SelectedEntry.Property = entry.Property; + SelectedEntry.Value = entry.Value; + SelectedEntry.IsActive = true; + + if (forceRefresh) + { + ApplyFilters(); + } + + Task.Run(SaveAsync); + } + + private void ApplyFilters() + { + var expressions = new List>>(4); + + if (!string.IsNullOrWhiteSpace(CategoryFilter)) + { + expressions.Add(entry => entry.Category.Contains((string) CategoryFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (!string.IsNullOrWhiteSpace(PropertyFilter)) + { + expressions.Add(entry => entry.Property.Contains((string) PropertyFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (!string.IsNullOrWhiteSpace(ValueFilter)) + { + expressions.Add(entry => entry.Value.Contains((string) ValueFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (ShowUserSettingsFilter) + { + expressions.Add(entry => entry.IsActive); + } + + if (expressions.Count == 0) + { + FilteredEntries = new ObservableCollection(Entries); + Filtered = false; + } + else + { + IEnumerable filtered = Entries; + foreach (var expression in expressions) + { + filtered = filtered.Where(expression.Compile()); + } + + FilteredEntries = new ObservableCollection(filtered.ToList()); + Filtered = true; + } + } + + private bool CanClearFiltersExecute() + { + return Filtered; + } + + private async Task SaveAsync() + { + try + { + await _configurator.WriteAsync(Entries); + } + catch (Exception exception) + { + const string message = "Failed to save configuration file"; + + logger.LogError(exception, message); + notificationService.ShowError(message, exception); + } + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Tools/SearchElementsViewModel.cs b/source/RevitLookup/ViewModels/Tools/SearchElementsViewModel.cs new file mode 100644 index 000000000..e31248b78 --- /dev/null +++ b/source/RevitLookup/ViewModels/Tools/SearchElementsViewModel.cs @@ -0,0 +1,31 @@ +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.ViewModels.Tools; +using RevitLookup.Core.Tools.Search; + +namespace RevitLookup.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class SearchElementsViewModel( + INotificationService notificationService, + IVisualDecompositionService decompositionService) + : ObservableObject, ISearchElementsViewModel +{ + [ObservableProperty] private string _searchText = string.Empty; + + public async Task SearchElementsAsync() + { + var result = SearchText != string.Empty; + if (result) + { + var elements = ElementsFinder.SearchElements(SearchText); + await decompositionService.VisualizeDecompositionAsync(elements); + } + else + { + notificationService.ShowWarning("Search elements", "There are no elements found for your request"); + } + + return result; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Tools/UnitsViewModel.cs b/source/RevitLookup/ViewModels/Tools/UnitsViewModel.cs new file mode 100644 index 000000000..3daa93732 --- /dev/null +++ b/source/RevitLookup/ViewModels/Tools/UnitsViewModel.cs @@ -0,0 +1,101 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics.CodeAnalysis; +using RevitLookup.Abstractions.Models.Tools; +using RevitLookup.Abstractions.Services.Decomposition; +using RevitLookup.Abstractions.ViewModels.Tools; +using RevitLookup.Core; +using RevitLookup.Core.Tools.Units; + +namespace RevitLookup.ViewModels.Tools; + +[UsedImplicitly] +public sealed partial class UnitsViewModel(IVisualDecompositionService decompositionService) : ObservableObject, IUnitsViewModel +{ + [ObservableProperty] private List _units = []; + [ObservableProperty] private List _filteredUnits = []; + [ObservableProperty] private string _searchText = string.Empty; + + public void InitializeParameters() + { + Units = UnitsCollector.GetBuiltinParametersInfo(); + } + + public void InitializeCategories() + { + Units = UnitsCollector.GetBuiltinCategoriesInfo(); + } + + public void InitializeForgeSchema() + { + Units = UnitsCollector.GetForgeInfo(); + } + + public async Task DecomposeAsync(UnitInfo unitInfo) + { + var obj = unitInfo.Value switch + { + BuiltInParameter parameter => RevitShell.GetBuiltinParameter(parameter), + BuiltInCategory category => RevitShell.GetBuiltinCategory(category), + _ => unitInfo.Value + }; + + await decompositionService.VisualizeDecompositionAsync(obj); + } + + [SuppressMessage("ReSharper", "ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator")] + async partial void OnSearchTextChanged(string value) + { + try + { + if (string.IsNullOrEmpty(SearchText)) + { + FilteredUnits = Units; + return; + } + + FilteredUnits = await Task.Run(() => + { + var formattedText = value.Trim(); + var searchResults = new List(); + foreach (var family in Units) + { + if (family.Label.Contains(formattedText, StringComparison.OrdinalIgnoreCase) || + family.Unit.Contains(formattedText, StringComparison.OrdinalIgnoreCase)) + { + searchResults.Add(family); + } + } + + return searchResults; + }); + } + catch + { + // ignored + } + } + + partial void OnUnitsChanged(List value) + { + FilteredUnits = value; + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/BoundingBoxVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/BoundingBoxVisualizationViewModel.cs new file mode 100644 index 000000000..72e217e58 --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/BoundingBoxVisualizationViewModel.cs @@ -0,0 +1,139 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class BoundingBoxVisualizationViewModel( + ISettingsService settingsService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IBoundingBoxVisualizationViewModel +{ + private readonly BoundingBoxVisualizationServer _server = new(); + + [ObservableProperty] private double _transparency = settingsService.RenderSettings.BoundingBoxSettings.Transparency; + + [ObservableProperty] private Color _surfaceColor = settingsService.RenderSettings.BoundingBoxSettings.SurfaceColor; + [ObservableProperty] private Color _edgeColor = settingsService.RenderSettings.BoundingBoxSettings.EdgeColor; + [ObservableProperty] private Color _axisColor = settingsService.RenderSettings.BoundingBoxSettings.AxisColor; + + [ObservableProperty] private bool _showSurface = settingsService.RenderSettings.BoundingBoxSettings.ShowSurface; + [ObservableProperty] private bool _showEdge = settingsService.RenderSettings.BoundingBoxSettings.ShowEdge; + [ObservableProperty] private bool _showAxis = settingsService.RenderSettings.BoundingBoxSettings.ShowAxis; + + public void RegisterServer(object boxObject) + { + if (boxObject is not BoundingBoxXYZ box) + { + throw new ArgumentException($"Argument must be of type {nameof(BoundingBoxXYZ)}", nameof(boxObject)); + } + + UpdateShowSurface(ShowSurface); + UpdateShowEdge(ShowEdge); + UpdateShowAxis(ShowAxis); + + UpdateSurfaceColor(SurfaceColor); + UpdateEdgeColor(EdgeColor); + UpdateAxisColor(AxisColor); + + UpdateTransparency(Transparency); + + _server.RenderFailed += HandleRenderFailure; + _server.Register(box); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.BoundingBoxSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnSurfaceColorChanged(Color value) + { + settingsService.RenderSettings.BoundingBoxSettings.SurfaceColor = value; + UpdateSurfaceColor(value); + } + + partial void OnEdgeColorChanged(Color value) + { + settingsService.RenderSettings.BoundingBoxSettings.EdgeColor = value; + UpdateEdgeColor(value); + } + + partial void OnAxisColorChanged(Color value) + { + settingsService.RenderSettings.BoundingBoxSettings.AxisColor = value; + UpdateAxisColor(value); + } + + partial void OnShowSurfaceChanged(bool value) + { + settingsService.RenderSettings.BoundingBoxSettings.ShowSurface = value; + UpdateShowSurface(value); + } + + partial void OnShowEdgeChanged(bool value) + { + settingsService.RenderSettings.BoundingBoxSettings.ShowEdge = value; + UpdateShowEdge(value); + } + + partial void OnShowAxisChanged(bool value) + { + settingsService.RenderSettings.BoundingBoxSettings.ShowEdge = value; + UpdateShowAxis(value); + } + + private void UpdateSurfaceColor(Color value) + { + _server.UpdateSurfaceColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateEdgeColor(Color value) + { + _server.UpdateEdgeColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateAxisColor(Color value) + { + _server.UpdateAxisColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateShowSurface(bool value) + { + _server.UpdateSurfaceVisibility(value); + } + + private void UpdateShowEdge(bool value) + { + _server.UpdateEdgeVisibility(value); + } + + private void UpdateShowAxis(bool value) + { + _server.UpdateAxisVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/FaceVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/FaceVisualizationViewModel.cs new file mode 100644 index 000000000..01404e3f5 --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/FaceVisualizationViewModel.cs @@ -0,0 +1,154 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class FaceVisualizationViewModel( + ISettingsService settingsService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IFaceVisualizationViewModel +{ + private readonly FaceVisualizationServer _server = new(); + + [ObservableProperty] private double _extrusion = settingsService.RenderSettings.FaceSettings.Extrusion; + [ObservableProperty] private double _transparency = settingsService.RenderSettings.FaceSettings.Transparency; + + [ObservableProperty] private Color _surfaceColor = settingsService.RenderSettings.FaceSettings.SurfaceColor; + [ObservableProperty] private Color _meshColor = settingsService.RenderSettings.FaceSettings.MeshColor; + [ObservableProperty] private Color _normalVectorColor = settingsService.RenderSettings.FaceSettings.NormalVectorColor; + + [ObservableProperty] private bool _showSurface = settingsService.RenderSettings.FaceSettings.ShowSurface; + [ObservableProperty] private bool _showMeshGrid = settingsService.RenderSettings.FaceSettings.ShowMeshGrid; + [ObservableProperty] private bool _showNormalVector = settingsService.RenderSettings.FaceSettings.ShowNormalVector; + + public double MinExtrusion => settingsService.RenderSettings.FaceSettings.MinExtrusion; + + public void RegisterServer(object faceObject) + { + if (faceObject is not Face face) + { + throw new ArgumentException($"Argument must be of type {nameof(Face)}", nameof(faceObject)); + } + + UpdateShowSurface(ShowSurface); + UpdateShowMeshGrid(ShowMeshGrid); + UpdateShowNormalVector(ShowNormalVector); + + UpdateSurfaceColor(SurfaceColor); + UpdateMeshColor(MeshColor); + UpdateNormalVectorColor(NormalVectorColor); + + UpdateTransparency(Transparency); + UpdateExtrusion(Extrusion); + + _server.RenderFailed += HandleRenderFailure; + _server.Register(face); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnSurfaceColorChanged(Color value) + { + settingsService.RenderSettings.FaceSettings.SurfaceColor = value; + UpdateSurfaceColor(value); + } + + partial void OnMeshColorChanged(Color value) + { + settingsService.RenderSettings.FaceSettings.MeshColor = value; + UpdateMeshColor(value); + } + + partial void OnNormalVectorColorChanged(Color value) + { + settingsService.RenderSettings.FaceSettings.NormalVectorColor = value; + UpdateNormalVectorColor(value); + } + + partial void OnExtrusionChanged(double value) + { + settingsService.RenderSettings.FaceSettings.Extrusion = value; + UpdateExtrusion(value); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.FaceSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnShowSurfaceChanged(bool value) + { + settingsService.RenderSettings.FaceSettings.ShowSurface = value; + UpdateShowSurface(value); + } + + partial void OnShowMeshGridChanged(bool value) + { + settingsService.RenderSettings.FaceSettings.ShowMeshGrid = value; + UpdateShowMeshGrid(value); + } + + partial void OnShowNormalVectorChanged(bool value) + { + settingsService.RenderSettings.FaceSettings.ShowNormalVector = value; + UpdateShowNormalVector(value); + } + + private void UpdateSurfaceColor(Color value) + { + _server.UpdateSurfaceColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateMeshColor(Color value) + { + _server.UpdateMeshGridColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateNormalVectorColor(Color value) + { + _server.UpdateNormalVectorColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateExtrusion(double value) + { + _server.UpdateExtrusion(value / 12); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateShowSurface(bool value) + { + _server.UpdateSurfaceVisibility(value); + } + + private void UpdateShowMeshGrid(bool value) + { + _server.UpdateMeshGridVisibility(value); + } + + private void UpdateShowNormalVector(bool value) + { + _server.UpdateNormalVectorVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/MeshVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/MeshVisualizationViewModel.cs new file mode 100644 index 000000000..361622d1f --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/MeshVisualizationViewModel.cs @@ -0,0 +1,154 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class MeshVisualizationViewModel( + ISettingsService settingsService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IMeshVisualizationViewModel +{ + private readonly MeshVisualizationServer _server = new(); + + [ObservableProperty] private double _extrusion = settingsService.RenderSettings.MeshSettings.Extrusion; + [ObservableProperty] private double _transparency = settingsService.RenderSettings.MeshSettings.Transparency; + + [ObservableProperty] private Color _surfaceColor = settingsService.RenderSettings.MeshSettings.SurfaceColor; + [ObservableProperty] private Color _meshColor = settingsService.RenderSettings.MeshSettings.MeshColor; + [ObservableProperty] private Color _normalVectorColor = settingsService.RenderSettings.MeshSettings.NormalVectorColor; + + [ObservableProperty] private bool _showSurface = settingsService.RenderSettings.MeshSettings.ShowSurface; + [ObservableProperty] private bool _showMeshGrid = settingsService.RenderSettings.MeshSettings.ShowMeshGrid; + [ObservableProperty] private bool _showNormalVector = settingsService.RenderSettings.MeshSettings.ShowNormalVector; + + public double MinExtrusion => settingsService.RenderSettings.MeshSettings.MinExtrusion; + + public void RegisterServer(object meshObject) + { + if (meshObject is not Mesh mesh) + { + throw new ArgumentException($"Argument must be of type {nameof(Mesh)}", nameof(meshObject)); + } + + UpdateShowSurface(ShowSurface); + UpdateShowMeshGrid(ShowMeshGrid); + UpdateShowNormalVector(ShowNormalVector); + + UpdateSurfaceColor(SurfaceColor); + UpdateMeshColor(MeshColor); + UpdateNormalVectorColor(NormalVectorColor); + + UpdateTransparency(Transparency); + UpdateExtrusion(Extrusion); + + _server.RenderFailed += HandleRenderFailure; + _server.Register(mesh); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnSurfaceColorChanged(Color value) + { + settingsService.RenderSettings.MeshSettings.SurfaceColor = value; + UpdateSurfaceColor(value); + } + + partial void OnMeshColorChanged(Color value) + { + settingsService.RenderSettings.MeshSettings.MeshColor = value; + UpdateMeshColor(value); + } + + partial void OnNormalVectorColorChanged(Color value) + { + settingsService.RenderSettings.MeshSettings.NormalVectorColor = value; + UpdateNormalVectorColor(value); + } + + partial void OnExtrusionChanged(double value) + { + settingsService.RenderSettings.MeshSettings.Extrusion = value; + UpdateExtrusion(value); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.MeshSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnShowSurfaceChanged(bool value) + { + settingsService.RenderSettings.MeshSettings.ShowSurface = value; + UpdateShowSurface(value); + } + + partial void OnShowMeshGridChanged(bool value) + { + settingsService.RenderSettings.MeshSettings.ShowMeshGrid = value; + UpdateShowMeshGrid(value); + } + + partial void OnShowNormalVectorChanged(bool value) + { + settingsService.RenderSettings.MeshSettings.ShowNormalVector = value; + UpdateShowNormalVector(value); + } + + private void UpdateSurfaceColor(Color value) + { + _server.UpdateSurfaceColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateMeshColor(Color value) + { + _server.UpdateMeshGridColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateNormalVectorColor(Color value) + { + _server.UpdateNormalVectorColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateExtrusion(double value) + { + _server.UpdateExtrusion(value / 12); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateShowSurface(bool value) + { + _server.UpdateSurfaceVisibility(value); + } + + private void UpdateShowMeshGrid(bool value) + { + _server.UpdateMeshGridVisibility(value); + } + + private void UpdateShowNormalVector(bool value) + { + _server.UpdateNormalVectorVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/PolylineVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/PolylineVisualizationViewModel.cs new file mode 100644 index 000000000..77cd3215c --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/PolylineVisualizationViewModel.cs @@ -0,0 +1,164 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using RevitLookup.UI.Framework.Services.Presentation; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class PolylineVisualizationViewModel( + NotificationService notificationService, + ISettingsService settingsService, + ILogger logger) + : ObservableObject, IPolylineVisualizationViewModel +{ + private readonly PolylineVisualizationServer _server = new(); + + [ObservableProperty] private double _diameter = settingsService.RenderSettings.PolylineSettings.Diameter; + [ObservableProperty] private double _transparency = settingsService.RenderSettings.PolylineSettings.Transparency; + + [ObservableProperty] private Color _surfaceColor = settingsService.RenderSettings.PolylineSettings.SurfaceColor; + [ObservableProperty] private Color _curveColor = settingsService.RenderSettings.PolylineSettings.CurveColor; + [ObservableProperty] private Color _directionColor = settingsService.RenderSettings.PolylineSettings.DirectionColor; + + [ObservableProperty] private bool _showSurface = settingsService.RenderSettings.PolylineSettings.ShowSurface; + [ObservableProperty] private bool _showCurve = settingsService.RenderSettings.PolylineSettings.ShowCurve; + [ObservableProperty] private bool _showDirection = settingsService.RenderSettings.PolylineSettings.ShowDirection; + + public double MinThickness => settingsService.RenderSettings.PolylineSettings.MinThickness; + + public void RegisterServer(object curveOrEdge) + { + Initialize(); + _server.RenderFailed += HandleRenderFailure; + + switch (curveOrEdge) + { + case Curve curve: + _server.Register(curve.Tessellate()); + break; + case Edge edge: + _server.Register(edge.Tessellate()); + break; + default: + throw new ArgumentException("Unexpected polyline type", nameof(curveOrEdge)); + } + } + + private void Initialize() + { + UpdateShowSurface(ShowSurface); + UpdateShowCurve(ShowCurve); + UpdateShowDirection(ShowDirection); + + UpdateSurfaceColor(SurfaceColor); + UpdateCurveColor(CurveColor); + UpdateDirectionColor(DirectionColor); + + UpdateTransparency(Transparency); + UpdateDiameter(Diameter); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnSurfaceColorChanged(Color value) + { + settingsService.RenderSettings.PolylineSettings.SurfaceColor = value; + UpdateSurfaceColor(value); + } + + partial void OnCurveColorChanged(Color value) + { + settingsService.RenderSettings.PolylineSettings.CurveColor = value; + UpdateCurveColor(value); + } + + partial void OnDirectionColorChanged(Color value) + { + settingsService.RenderSettings.PolylineSettings.DirectionColor = value; + UpdateDirectionColor(value); + } + + partial void OnDiameterChanged(double value) + { + settingsService.RenderSettings.PolylineSettings.Diameter = value; + UpdateDiameter(value); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.PolylineSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnShowSurfaceChanged(bool value) + { + settingsService.RenderSettings.PolylineSettings.ShowSurface = value; + UpdateShowSurface(value); + } + + partial void OnShowCurveChanged(bool value) + { + settingsService.RenderSettings.PolylineSettings.ShowCurve = value; + UpdateShowCurve(value); + } + + partial void OnShowDirectionChanged(bool value) + { + settingsService.RenderSettings.PolylineSettings.ShowDirection = value; + UpdateShowDirection(value); + } + + private void UpdateSurfaceColor(Color value) + { + _server.UpdateSurfaceColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateCurveColor(Color value) + { + _server.UpdateCurveColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateDirectionColor(Color value) + { + _server.UpdateDirectionColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateDiameter(double value) + { + _server.UpdateDiameter(value / 12); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateShowSurface(bool value) + { + _server.UpdateSurfaceVisibility(value); + } + + private void UpdateShowCurve(bool value) + { + _server.UpdateCurveVisibility(value); + } + + private void UpdateShowDirection(bool value) + { + _server.UpdateDirectionVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/SolidVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/SolidVisualizationViewModel.cs new file mode 100644 index 000000000..6b473a0ec --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/SolidVisualizationViewModel.cs @@ -0,0 +1,126 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class SolidVisualizationViewModel( + ISettingsService settingsService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, ISolidVisualizationViewModel +{ + private readonly SolidVisualizationServer _server = new(); + + [ObservableProperty] private double _scale = settingsService.RenderSettings.SolidSettings.Scale; + [ObservableProperty] private double _transparency = settingsService.RenderSettings.SolidSettings.Transparency; + + [ObservableProperty] private Color _faceColor = settingsService.RenderSettings.SolidSettings.FaceColor; + [ObservableProperty] private Color _edgeColor = settingsService.RenderSettings.SolidSettings.EdgeColor; + + [ObservableProperty] private bool _showFace = settingsService.RenderSettings.SolidSettings.ShowFace; + [ObservableProperty] private bool _showEdge = settingsService.RenderSettings.SolidSettings.ShowEdge; + + public void RegisterServer(object solidObject) + { + if (solidObject is not Solid solid) + { + throw new ArgumentException($"Argument must be of type {nameof(Solid)}", nameof(solidObject)); + } + + UpdateShowFace(ShowFace); + UpdateShowEdge(ShowEdge); + + UpdateFaceColor(FaceColor); + UpdateEdgeColor(EdgeColor); + + UpdateTransparency(Transparency); + UpdateScale(Scale); + + _server.RenderFailed += HandleRenderFailure; + _server.Register(solid); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnFaceColorChanged(Color value) + { + settingsService.RenderSettings.SolidSettings.FaceColor = value; + UpdateFaceColor(value); + } + + partial void OnEdgeColorChanged(Color value) + { + settingsService.RenderSettings.SolidSettings.EdgeColor = value; + UpdateEdgeColor(value); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.SolidSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnScaleChanged(double value) + { + settingsService.RenderSettings.SolidSettings.Scale = value; + UpdateScale(value); + } + + partial void OnShowFaceChanged(bool value) + { + settingsService.RenderSettings.SolidSettings.ShowFace = value; + UpdateShowFace(value); + } + + partial void OnShowEdgeChanged(bool value) + { + settingsService.RenderSettings.SolidSettings.ShowEdge = value; + UpdateShowEdge(value); + } + + private void UpdateFaceColor(Color value) + { + _server.UpdateFaceColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateEdgeColor(Color value) + { + _server.UpdateEdgeColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateScale(double value) + { + _server.UpdateScale(value / 100); + } + + private void UpdateShowFace(bool value) + { + _server.UpdateFaceVisibility(value); + } + + private void UpdateShowEdge(bool value) + { + _server.UpdateEdgeVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/ViewModels/Visualization/XyzVisualizationViewModel.cs b/source/RevitLookup/ViewModels/Visualization/XyzVisualizationViewModel.cs new file mode 100644 index 000000000..334ade5a1 --- /dev/null +++ b/source/RevitLookup/ViewModels/Visualization/XyzVisualizationViewModel.cs @@ -0,0 +1,167 @@ +using Microsoft.Extensions.Logging; +using RevitLookup.Abstractions.Services.Presentation; +using RevitLookup.Abstractions.Services.Settings; +using RevitLookup.Abstractions.ViewModels.Visualization; +using RevitLookup.Core.Visualization; +using RevitLookup.Core.Visualization.Events; +using Color = System.Windows.Media.Color; + +namespace RevitLookup.ViewModels.Visualization; + +[UsedImplicitly] +public sealed partial class XyzVisualizationViewModel( + ISettingsService settingsService, + INotificationService notificationService, + ILogger logger) + : ObservableObject, IXyzVisualizationViewModel +{ + private readonly XyzVisualizationServer _server = new(); + + [ObservableProperty] private double _axisLength = settingsService.RenderSettings.XyzSettings.AxisLength; + [ObservableProperty] private double _transparency = settingsService.RenderSettings.XyzSettings.Transparency; + + [ObservableProperty] private Color _xColor = settingsService.RenderSettings.XyzSettings.XColor; + [ObservableProperty] private Color _yColor = settingsService.RenderSettings.XyzSettings.YColor; + [ObservableProperty] private Color _zColor = settingsService.RenderSettings.XyzSettings.ZColor; + + [ObservableProperty] private bool _showPlane = settingsService.RenderSettings.XyzSettings.ShowPlane; + [ObservableProperty] private bool _showXAxis = settingsService.RenderSettings.XyzSettings.ShowXAxis; + [ObservableProperty] private bool _showYAxis = settingsService.RenderSettings.XyzSettings.ShowYAxis; + [ObservableProperty] private bool _showZAxis = settingsService.RenderSettings.XyzSettings.ShowZAxis; + + public double MinAxisLength => settingsService.RenderSettings.XyzSettings.MinAxisLength; + + public void RegisterServer(object xyzObject) + { + if (xyzObject is not XYZ point) + { + throw new ArgumentException($"Argument must be of type {nameof(XYZ)}", nameof(xyzObject)); + } + + UpdateShowPlane(ShowPlane); + UpdateShowXAxis(ShowXAxis); + UpdateShowYAxis(ShowYAxis); + UpdateShowZAxis(ShowZAxis); + + UpdateXColor(XColor); + UpdateYColor(YColor); + UpdateZColor(ZColor); + + UpdateAxisLength(AxisLength); + UpdateTransparency(Transparency); + + _server.RenderFailed += HandleRenderFailure; + _server.Register(point); + } + + public void UnregisterServer() + { + _server.RenderFailed -= HandleRenderFailure; + _server.Unregister(); + } + + private void HandleRenderFailure(object? sender, RenderFailedEventArgs args) + { + logger.LogError(args.ExceptionObject, "Render error"); + notificationService.ShowError("Render error", args.ExceptionObject); + } + + partial void OnXColorChanged(Color value) + { + settingsService.RenderSettings.XyzSettings.XColor = value; + UpdateXColor(value); + } + + partial void OnYColorChanged(Color value) + { + settingsService.RenderSettings.XyzSettings.YColor = value; + UpdateYColor(value); + } + + partial void OnZColorChanged(Color value) + { + settingsService.RenderSettings.XyzSettings.ZColor = value; + UpdateZColor(value); + } + + partial void OnAxisLengthChanged(double value) + { + settingsService.RenderSettings.XyzSettings.AxisLength = value; + UpdateAxisLength(value); + } + + partial void OnTransparencyChanged(double value) + { + settingsService.RenderSettings.XyzSettings.Transparency = value; + UpdateTransparency(value); + } + + partial void OnShowPlaneChanged(bool value) + { + settingsService.RenderSettings.XyzSettings.ShowPlane = value; + UpdateShowPlane(value); + } + + partial void OnShowXAxisChanged(bool value) + { + settingsService.RenderSettings.XyzSettings.ShowXAxis = value; + UpdateShowXAxis(value); + } + + partial void OnShowYAxisChanged(bool value) + { + settingsService.RenderSettings.XyzSettings.ShowYAxis = value; + UpdateShowYAxis(value); + } + + partial void OnShowZAxisChanged(bool value) + { + settingsService.RenderSettings.XyzSettings.ShowZAxis = value; + UpdateShowZAxis(value); + } + + private void UpdateXColor(Color value) + { + _server.UpdateXColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateYColor(Color value) + { + _server.UpdateYColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateZColor(Color value) + { + _server.UpdateZColor(new Autodesk.Revit.DB.Color(value.R, value.G, value.B)); + } + + private void UpdateAxisLength(double value) + { + _server.UpdateAxisLength(value / 12); + } + + private void UpdateTransparency(double value) + { + _server.UpdateTransparency(value / 100); + } + + private void UpdateShowPlane(bool value) + { + _server.UpdatePlaneVisibility(value); + } + + private void UpdateShowXAxis(bool value) + { + _server.UpdateXAxisVisibility(value); + } + + private void UpdateShowYAxis(bool value) + { + _server.UpdateYAxisVisibility(value); + } + + private void UpdateShowZAxis(bool value) + { + _server.UpdateZAxisVisibility(value); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Views/Pages/AboutPage.xaml b/source/RevitLookup/Views/Pages/AboutPage.xaml deleted file mode 100644 index cafcd7d50..000000000 --- a/source/RevitLookup/Views/Pages/AboutPage.xaml +++ /dev/null @@ -1,227 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/RevitLookupObsolete/.editorconfig b/source/RevitLookupObsolete/.editorconfig new file mode 100644 index 000000000..557d19427 --- /dev/null +++ b/source/RevitLookupObsolete/.editorconfig @@ -0,0 +1,590 @@ +[*] +charset = utf-8 +end_of_line = crlf +trim_trailing_whitespace = false +insert_final_newline = false +indent_style = space +indent_size = 4 + +# Microsoft .NET properties +csharp_indent_braces = false +csharp_indent_switch_labels = true +csharp_new_line_before_catch = true +csharp_new_line_before_else = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_open_brace = all +csharp_new_line_between_query_expression_clauses = true +csharp_preferred_modifier_order = public, private, protected, internal, file, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async, required:suggestion +csharp_preserve_single_line_blocks = true +csharp_space_after_cast = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_using_directive_placement = outside_namespace:silent +dotnet_naming_rule.constants_rule.severity = warning +dotnet_naming_rule.constants_rule.style = upper_camel_case_style +dotnet_naming_rule.constants_rule.symbols = constants_symbols +dotnet_naming_rule.event_rule.severity = warning +dotnet_naming_rule.event_rule.style = upper_camel_case_style +dotnet_naming_rule.event_rule.symbols = event_symbols +dotnet_naming_rule.interfaces_rule.severity = warning +dotnet_naming_rule.interfaces_rule.style = i_upper_camel_case_style +dotnet_naming_rule.interfaces_rule.symbols = interfaces_symbols +dotnet_naming_rule.locals_rule.severity = warning +dotnet_naming_rule.locals_rule.style = lower_camel_case_style_1 +dotnet_naming_rule.locals_rule.symbols = locals_symbols +dotnet_naming_rule.local_constants_rule.severity = warning +dotnet_naming_rule.local_constants_rule.style = lower_camel_case_style_1 +dotnet_naming_rule.local_constants_rule.symbols = local_constants_symbols +dotnet_naming_rule.local_functions_rule.severity = warning +dotnet_naming_rule.local_functions_rule.style = upper_camel_case_style +dotnet_naming_rule.local_functions_rule.symbols = local_functions_symbols +dotnet_naming_rule.method_rule.severity = warning +dotnet_naming_rule.method_rule.style = upper_camel_case_style +dotnet_naming_rule.method_rule.symbols = method_symbols +dotnet_naming_rule.parameters_rule.severity = warning +dotnet_naming_rule.parameters_rule.style = lower_camel_case_style_1 +dotnet_naming_rule.parameters_rule.symbols = parameters_symbols +dotnet_naming_rule.private_constants_rule.severity = warning +dotnet_naming_rule.private_constants_rule.style = upper_camel_case_style +dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols +dotnet_naming_rule.private_instance_fields_rule.severity = warning +dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols +dotnet_naming_rule.private_static_fields_rule.severity = warning +dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style +dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols +dotnet_naming_rule.private_static_readonly_rule.severity = warning +dotnet_naming_rule.private_static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols +dotnet_naming_rule.property_rule.severity = warning +dotnet_naming_rule.property_rule.style = upper_camel_case_style +dotnet_naming_rule.property_rule.symbols = property_symbols +dotnet_naming_rule.public_fields_rule.severity = warning +dotnet_naming_rule.public_fields_rule.style = upper_camel_case_style +dotnet_naming_rule.public_fields_rule.symbols = public_fields_symbols +dotnet_naming_rule.static_readonly_rule.severity = warning +dotnet_naming_rule.static_readonly_rule.style = upper_camel_case_style +dotnet_naming_rule.static_readonly_rule.symbols = static_readonly_symbols +dotnet_naming_rule.types_and_namespaces_rule.severity = warning +dotnet_naming_rule.types_and_namespaces_rule.style = upper_camel_case_style +dotnet_naming_rule.types_and_namespaces_rule.symbols = types_and_namespaces_symbols +dotnet_naming_rule.type_parameters_rule.severity = warning +dotnet_naming_rule.type_parameters_rule.style = t_upper_camel_case_style +dotnet_naming_rule.type_parameters_rule.symbols = type_parameters_symbols +dotnet_naming_style.i_upper_camel_case_style.capitalization = pascal_case +dotnet_naming_style.i_upper_camel_case_style.required_prefix = I +dotnet_naming_style.lower_camel_case_style.capitalization = camel_case +dotnet_naming_style.lower_camel_case_style.required_prefix = _ +dotnet_naming_style.lower_camel_case_style_1.capitalization = camel_case +dotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case +dotnet_naming_style.t_upper_camel_case_style.required_prefix = T +dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case +dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.constants_symbols.applicable_kinds = field +dotnet_naming_symbols.constants_symbols.required_modifiers = const +dotnet_naming_symbols.event_symbols.applicable_accessibilities = * +dotnet_naming_symbols.event_symbols.applicable_kinds = event +dotnet_naming_symbols.interfaces_symbols.applicable_accessibilities = * +dotnet_naming_symbols.interfaces_symbols.applicable_kinds = interface +dotnet_naming_symbols.locals_symbols.applicable_accessibilities = * +dotnet_naming_symbols.locals_symbols.applicable_kinds = local +dotnet_naming_symbols.local_constants_symbols.applicable_accessibilities = * +dotnet_naming_symbols.local_constants_symbols.applicable_kinds = local +dotnet_naming_symbols.local_constants_symbols.required_modifiers = const +dotnet_naming_symbols.local_functions_symbols.applicable_accessibilities = * +dotnet_naming_symbols.local_functions_symbols.applicable_kinds = local_function +dotnet_naming_symbols.method_symbols.applicable_accessibilities = * +dotnet_naming_symbols.method_symbols.applicable_kinds = method +dotnet_naming_symbols.parameters_symbols.applicable_accessibilities = * +dotnet_naming_symbols.parameters_symbols.applicable_kinds = parameter +dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field +dotnet_naming_symbols.private_constants_symbols.required_modifiers = const +dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static +dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly +dotnet_naming_symbols.property_symbols.applicable_accessibilities = * +dotnet_naming_symbols.property_symbols.applicable_kinds = property +dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field +dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected +dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field +dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static, readonly +dotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = * +dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace, class, struct, enum, delegate +dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = true +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion +dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion + +# ReSharper properties +resharper_accessor_owner_body = expression_body +resharper_alignment_tab_fill_style = use_spaces +resharper_align_first_arg_by_paren = false +resharper_align_linq_query = false +resharper_align_multiline_array_and_object_initializer = false +resharper_align_multiline_array_initializer = true +resharper_align_multiline_binary_patterns = false +resharper_align_multiline_ctor_init = true +resharper_align_multiline_expression_braces = false +resharper_align_multiline_implements_list = true +resharper_align_multiline_property_pattern = false +resharper_align_multiline_statement_conditions = true +resharper_align_multiline_switch_expression = false +resharper_align_multiline_type_argument = true +resharper_align_multiline_type_parameter = true +resharper_align_multline_type_parameter_constrains = false +resharper_align_multline_type_parameter_list = false +resharper_align_ternary = align_not_nested +resharper_align_tuple_components = false +resharper_allow_alias = true +resharper_allow_comment_after_lbrace = false +resharper_allow_far_alignment = false +resharper_arguments_anonymous_function = positional +resharper_arguments_literal = positional +resharper_arguments_named = positional +resharper_arguments_other = positional +resharper_arguments_skip_single = false +resharper_arguments_string_literal = positional +resharper_blank_lines_after_block_statements = 1 +resharper_blank_lines_after_case = 0 +resharper_blank_lines_after_control_transfer_statements = 0 +resharper_blank_lines_after_file_scoped_namespace_directive = 1 +resharper_blank_lines_after_imports = 1 +resharper_blank_lines_after_multiline_statements = 0 +resharper_blank_lines_after_options = 1 +resharper_blank_lines_after_start_comment = 1 +resharper_blank_lines_after_using_list = 1 +resharper_blank_lines_around_accessor = 0 +resharper_blank_lines_around_auto_property = 1 +resharper_blank_lines_around_block_case_section = 0 +resharper_blank_lines_around_class_definition = 1 +resharper_blank_lines_around_field = 1 +resharper_blank_lines_around_function_declaration = 0 +resharper_blank_lines_around_function_definition = 1 +resharper_blank_lines_around_global_attribute = 0 +resharper_blank_lines_around_invocable = 1 +resharper_blank_lines_around_local_method = 1 +resharper_blank_lines_around_multiline_case_section = 0 +resharper_blank_lines_around_namespace = 1 +resharper_blank_lines_around_other_declaration = 0 +resharper_blank_lines_around_property = 1 +resharper_blank_lines_around_region = 1 +resharper_blank_lines_around_single_line_accessor = 0 +resharper_blank_lines_around_single_line_auto_property = 0 +resharper_blank_lines_around_single_line_field = 0 +resharper_blank_lines_around_single_line_function_definition = 0 +resharper_blank_lines_around_single_line_invocable = 0 +resharper_blank_lines_around_single_line_local_method = 0 +resharper_blank_lines_around_single_line_property = 0 +resharper_blank_lines_around_single_line_type = 1 +resharper_blank_lines_around_type = 1 +resharper_blank_lines_before_block_statements = 0 +resharper_blank_lines_before_case = 0 +resharper_blank_lines_before_control_transfer_statements = 0 +resharper_blank_lines_before_multiline_statements = 0 +resharper_blank_lines_before_single_line_comment = 0 +resharper_blank_lines_inside_namespace = 0 +resharper_blank_lines_inside_region = 1 +resharper_blank_lines_inside_type = 0 +resharper_blank_line_after_pi = true +resharper_braces_for_dowhile = required +resharper_braces_for_fixed = required +resharper_braces_for_for = not_required +resharper_braces_for_foreach = not_required +resharper_braces_for_ifelse = not_required_for_both +resharper_braces_for_lock = required +resharper_braces_for_using = required +resharper_braces_for_while = not_required +resharper_braces_redundant = true +resharper_break_template_declaration = line_break +resharper_can_use_global_alias = true +resharper_constructor_or_destructor_body = block_body +resharper_continuous_indent_multiplier = 1 +resharper_continuous_line_indent = single +resharper_csharp_align_multiline_argument = false +resharper_csharp_align_multiline_binary_expressions_chain = true +resharper_csharp_align_multiline_calls_chain = false +resharper_csharp_align_multiline_expression = false +resharper_csharp_align_multiline_extends_list = false +resharper_csharp_align_multiline_for_stmt = false +resharper_csharp_align_multiline_parameter = false +resharper_csharp_align_multiple_declaration = false +resharper_csharp_insert_final_newline = false +resharper_csharp_new_line_before_while = false +resharper_csharp_prefer_qualified_reference = false +resharper_csharp_space_after_unary_operator = false +resharper_default_value_when_type_evident = default_literal +resharper_default_value_when_type_not_evident = default_literal +resharper_disable_space_changes_before_trailing_comment = false +resharper_empty_block_style = multiline +resharper_expression_braces = inside +resharper_extra_spaces = remove_all +resharper_force_attribute_style = separate +resharper_force_chop_compound_do_expression = false +resharper_force_chop_compound_if_expression = false +resharper_force_chop_compound_while_expression = false +resharper_function_declaration_return_type_style = do_not_change +resharper_function_definition_return_type_style = do_not_change +resharper_indent_access_specifiers_from_class = false +resharper_indent_aligned_ternary = true +resharper_indent_anonymous_method_block = false +resharper_indent_braces_inside_statement_conditions = true +resharper_indent_case_from_select = true +resharper_indent_child_elements = OneIndent +resharper_indent_class_members_from_access_specifiers = false +resharper_indent_comment = true +resharper_indent_inside_namespace = true +resharper_indent_invocation_pars = inside +resharper_indent_method_decl_pars = inside +resharper_indent_nested_fixed_stmt = false +resharper_indent_nested_foreach_stmt = false +resharper_indent_nested_for_stmt = false +resharper_indent_nested_lock_stmt = false +resharper_indent_nested_usings_stmt = false +resharper_indent_nested_while_stmt = false +resharper_indent_pars = inside +resharper_indent_preprocessor_directives = none +resharper_indent_preprocessor_if = no_indent +resharper_indent_preprocessor_other = no_indent +resharper_indent_preprocessor_region = usual_indent +resharper_indent_statement_pars = inside +resharper_indent_text = OneIndent +resharper_indent_typearg_angles = inside +resharper_indent_typeparam_angles = inside +resharper_indent_type_constraints = true +resharper_indent_wrapped_function_names = false +resharper_instance_members_qualify_declared_in = this_class, base_class +resharper_int_align = false +resharper_int_align_comments = false +resharper_int_align_declaration_names = false +resharper_int_align_eq = false +resharper_int_align_fix_in_adjacent = true +resharper_keep_blank_lines_in_code = 2 +resharper_keep_blank_lines_in_declarations = 2 +resharper_keep_existing_attribute_arrangement = false +resharper_keep_existing_declaration_block_arrangement = false +resharper_keep_existing_declaration_parens_arrangement = true +resharper_keep_existing_embedded_arrangement = true +resharper_keep_existing_embedded_block_arrangement = false +resharper_keep_existing_enum_arrangement = false +resharper_keep_existing_expr_member_arrangement = true +resharper_keep_existing_invocation_parens_arrangement = true +resharper_keep_existing_property_patterns_arrangement = true +resharper_keep_existing_switch_expression_arrangement = true +resharper_keep_user_linebreaks = true +resharper_linebreaks_inside_tags_for_elements_longer_than = 2147483647 +resharper_linebreaks_inside_tags_for_elements_with_child_elements = true +resharper_linebreaks_inside_tags_for_multiline_elements = true +resharper_linebreak_before_multiline_elements = true +resharper_linebreak_before_singleline_elements = false +resharper_line_break_after_colon_in_member_initializer_lists = do_not_change +resharper_line_break_after_comma_in_member_initializer_lists = false +resharper_line_break_before_comma_in_member_initializer_lists = false +resharper_line_break_before_requires_clause = do_not_change +resharper_linkage_specification_braces = end_of_line +resharper_linkage_specification_indentation = none +resharper_local_function_body = block_body +resharper_max_array_initializer_elements_on_line = 10000 +resharper_max_attribute_length_for_same_line = 120 +resharper_max_enum_members_on_line = 3 +resharper_max_formal_parameters_on_line = 10000 +resharper_max_initializer_elements_on_line = 4 +resharper_max_invocation_arguments_on_line = 10000 +resharper_member_initializer_list_style = do_not_change +resharper_method_or_operator_body = block_body +resharper_namespace_declaration_braces = next_line +resharper_namespace_indentation = all +resharper_nested_ternary_style = autodetect +resharper_new_line_before_catch = true +resharper_new_line_before_else = true +resharper_object_creation_when_type_evident = target_typed +resharper_object_creation_when_type_not_evident = explicitly_typed +resharper_old_engine = false +resharper_outdent_binary_ops = false +resharper_outdent_binary_pattern_ops = false +resharper_outdent_commas = false +resharper_outdent_dots = false +resharper_outdent_statement_labels = false +resharper_parentheses_non_obvious_operations = none, shift, bitwise_and, bitwise_exclusive_or, bitwise_inclusive_or, bitwise +resharper_parentheses_redundancy_style = remove_if_not_clarifies_precedence +resharper_parentheses_same_type_operations = false +resharper_pi_attributes_indent = align_by_first_attribute +resharper_place_accessorholder_attribute_on_same_line = if_owner_is_single_line +resharper_place_accessor_attribute_on_same_line = if_owner_is_single_line +resharper_place_comments_at_first_column = false +resharper_place_constructor_initializer_on_same_line = true +resharper_place_event_attribute_on_same_line = false +resharper_place_expr_accessor_on_single_line = if_owner_is_single_line +resharper_place_expr_method_on_single_line = if_owner_is_single_line +resharper_place_expr_property_on_single_line = if_owner_is_single_line +resharper_place_field_attribute_on_same_line = true +resharper_place_linq_into_on_new_line = true +resharper_place_method_attribute_on_same_line = false +resharper_place_namespace_definitions_on_same_line = false +resharper_place_property_attribute_on_same_line = false +resharper_place_simple_case_statement_on_same_line = false +resharper_place_simple_embedded_statement_on_same_line = if_owner_is_single_line +resharper_place_simple_initializer_on_single_line = true +resharper_place_simple_property_pattern_on_single_line = true +resharper_place_simple_switch_expression_on_single_line = false +resharper_place_type_attribute_on_same_line = false +resharper_place_type_constraints_on_same_line = true +resharper_prefer_explicit_discard_declaration = false +resharper_prefer_separate_deconstructed_variables_declaration = false +resharper_qualified_using_at_nested_scope = false +resharper_remove_blank_lines_near_braces_in_code = true +resharper_remove_blank_lines_near_braces_in_declarations = true +resharper_requires_expression_braces = next_line +resharper_simple_block_style = do_not_change +resharper_simple_case_statement_style = do_not_change +resharper_simple_embedded_statement_style = do_not_change +resharper_spaces_around_eq_in_attribute = false +resharper_spaces_around_eq_in_pi_attribute = false +resharper_spaces_inside_tags = false +resharper_space_after_attributes = true +resharper_space_after_attribute_target_colon = true +resharper_space_after_colon = true +resharper_space_after_colon_in_case = true +resharper_space_after_colon_in_inheritance_clause = true +resharper_space_after_comma = true +resharper_space_after_for_colon = true +resharper_space_after_keywords_in_control_flow_statements = true +resharper_space_after_last_attribute = false +resharper_space_after_last_pi_attribute = false +resharper_space_after_operator_keyword = true +resharper_space_after_ptr_in_data_member = true +resharper_space_after_ptr_in_data_members = false +resharper_space_after_ptr_in_method = true +resharper_space_after_ref_in_data_member = true +resharper_space_after_ref_in_data_members = false +resharper_space_after_ref_in_method = true +resharper_space_after_semicolon_in_for_statement = true +resharper_space_after_ternary_colon = true +resharper_space_after_ternary_quest = true +resharper_space_after_type_parameter_constraint_colon = true +resharper_space_around_additive_op = true +resharper_space_around_alias_eq = true +resharper_space_around_assignment_op = true +resharper_space_around_assignment_operator = true +resharper_space_around_deref_in_trailing_return_type = true +resharper_space_around_lambda_arrow = true +resharper_space_around_member_access_operator = false +resharper_space_around_relational_op = true +resharper_space_around_shift_op = true +resharper_space_around_stmt_colon = true +resharper_space_around_ternary_operator = true +resharper_space_before_array_rank_parentheses = false +resharper_space_before_attribute_target_colon = false +resharper_space_before_checked_parentheses = false +resharper_space_before_colon = false +resharper_space_before_colon_in_case = false +resharper_space_before_colon_in_inheritance_clause = true +resharper_space_before_comma = false +resharper_space_before_default_parentheses = false +resharper_space_before_empty_invocation_parentheses = false +resharper_space_before_empty_method_parentheses = false +resharper_space_before_for_colon = true +resharper_space_before_initializer_braces = false +resharper_space_before_invocation_parentheses = false +resharper_space_before_label_colon = false +resharper_space_before_lambda_parentheses = false +resharper_space_before_method_parentheses = false +resharper_space_before_nameof_parentheses = false +resharper_space_before_new_parentheses = false +resharper_space_before_nullable_mark = false +resharper_space_before_open_square_brackets = false +resharper_space_before_pointer_asterik_declaration = false +resharper_space_before_ptr_in_abstract_decl = false +resharper_space_before_ptr_in_data_member = false +resharper_space_before_ptr_in_data_members = true +resharper_space_before_ptr_in_method = false +resharper_space_before_ref_in_abstract_decl = false +resharper_space_before_ref_in_data_member = false +resharper_space_before_ref_in_data_members = true +resharper_space_before_ref_in_method = false +resharper_space_before_semicolon = false +resharper_space_before_semicolon_in_for_statement = false +resharper_space_before_singleline_accessorholder = true +resharper_space_before_sizeof_parentheses = false +resharper_space_before_template_args = false +resharper_space_before_template_params = true +resharper_space_before_ternary_colon = true +resharper_space_before_ternary_quest = true +resharper_space_before_trailing_comment = true +resharper_space_before_typeof_parentheses = false +resharper_space_before_type_argument_angle = false +resharper_space_before_type_parameter_angle = false +resharper_space_before_type_parameter_constraint_colon = true +resharper_space_before_type_parameter_parentheses = true +resharper_space_between_accessors_in_singleline_property = true +resharper_space_between_attribute_sections = true +resharper_space_between_closing_angle_brackets_in_template_args = false +resharper_space_between_keyword_and_expression = true +resharper_space_between_keyword_and_type = true +resharper_space_between_method_call_empty_parameter_list_parentheses = false +resharper_space_between_method_call_name_and_opening_parenthesis = false +resharper_space_between_method_call_parameter_list_parentheses = false +resharper_space_between_method_declaration_empty_parameter_list_parentheses = false +resharper_space_between_method_declaration_name_and_open_parenthesis = false +resharper_space_between_method_declaration_parameter_list_parentheses = false +resharper_space_between_parentheses_of_control_flow_statements = false +resharper_space_between_square_brackets = false +resharper_space_between_typecast_parentheses = false +resharper_space_in_singleline_accessorholder = true +resharper_space_in_singleline_anonymous_method = true +resharper_space_in_singleline_method = true +resharper_space_near_postfix_and_prefix_op = false +resharper_space_within_array_initialization_braces = false +resharper_space_within_array_rank_empty_parentheses = false +resharper_space_within_array_rank_parentheses = false +resharper_space_within_attribute_angles = false +resharper_space_within_checked_parentheses = false +resharper_space_within_default_parentheses = false +resharper_space_within_empty_braces = true +resharper_space_within_empty_initializer_braces = false +resharper_space_within_empty_invocation_parentheses = false +resharper_space_within_empty_method_parentheses = false +resharper_space_within_empty_template_params = false +resharper_space_within_expression_parentheses = false +resharper_space_within_initializer_braces = false +resharper_space_within_invocation_parentheses = false +resharper_space_within_method_parentheses = false +resharper_space_within_nameof_parentheses = false +resharper_space_within_new_parentheses = false +resharper_space_within_parentheses = false +resharper_space_within_single_line_array_initializer_braces = false +resharper_space_within_sizeof_parentheses = false +resharper_space_within_template_args = false +resharper_space_within_template_params = false +resharper_space_within_tuple_parentheses = false +resharper_space_within_typeof_parentheses = false +resharper_space_within_type_argument_angles = false +resharper_space_within_type_parameter_angles = false +resharper_space_within_type_parameter_parentheses = false +resharper_special_else_if_treatment = true +resharper_static_members_qualify_members = none +resharper_static_members_qualify_with = declared_type +resharper_stick_comment = true +resharper_toplevel_function_declaration_return_type_style = do_not_change +resharper_toplevel_function_definition_return_type_style = do_not_change +resharper_trailing_comma_in_multiline_lists = false +resharper_trailing_comma_in_singleline_lists = false +resharper_use_continuous_indent_inside_initializer_braces = true +resharper_use_continuous_indent_inside_parens = true +resharper_use_continuous_line_indent_in_expression_braces = false +resharper_use_continuous_line_indent_in_method_pars = false +resharper_use_heuristics_for_body_style = true +resharper_use_indent_from_previous_element = true +resharper_use_roslyn_logic_for_evident_types = false +resharper_vb_align_multiline_argument = true +resharper_vb_align_multiline_expression = true +resharper_vb_align_multiline_parameter = true +resharper_vb_align_multiple_declaration = true +resharper_vb_place_field_attribute_on_same_line = true +resharper_vb_place_method_attribute_on_same_line = false +resharper_vb_place_type_attribute_on_same_line = false +resharper_vb_prefer_qualified_reference = false +resharper_vb_space_after_unary_operator = true +resharper_vb_space_around_multiplicative_op = false +resharper_wrap_after_declaration_lpar = false +resharper_wrap_after_dot_in_method_calls = false +resharper_wrap_after_expression_lbrace = true +resharper_wrap_after_invocation_lpar = false +resharper_wrap_arguments_style = wrap_if_long +resharper_wrap_around_elements = true +resharper_wrap_array_initializer_style = wrap_if_long +resharper_wrap_base_clause_style = wrap_if_long +resharper_wrap_before_arrow_with_expressions = false +resharper_wrap_before_binary_opsign = false +resharper_wrap_before_binary_pattern_op = true +resharper_wrap_before_colon = false +resharper_wrap_before_comma = false +resharper_wrap_before_comma_in_base_clause = false +resharper_wrap_before_declaration_lpar = false +resharper_wrap_before_declaration_rpar = false +resharper_wrap_before_eq = false +resharper_wrap_before_expression_rbrace = true +resharper_wrap_before_extends_colon = false +resharper_wrap_before_first_type_parameter_constraint = false +resharper_wrap_before_invocation_lpar = false +resharper_wrap_before_invocation_rpar = false +resharper_wrap_before_linq_expression = false +resharper_wrap_before_ternary_opsigns = true +resharper_wrap_before_type_parameter_langle = false +resharper_wrap_braced_init_list_style = wrap_if_long +resharper_wrap_chained_binary_expressions = wrap_if_long +resharper_wrap_chained_binary_patterns = wrap_if_long +resharper_wrap_chained_method_calls = wrap_if_long +resharper_wrap_ctor_initializer_style = wrap_if_long +resharper_wrap_enumeration_style = chop_if_long +resharper_wrap_enum_declaration = chop_always +resharper_wrap_extends_list_style = wrap_if_long +resharper_wrap_for_stmt_header_style = chop_if_long +resharper_wrap_linq_expressions = chop_always +resharper_wrap_multiple_declaration_style = chop_if_long +resharper_wrap_multiple_type_parameter_constraints_style = chop_if_long +resharper_wrap_object_and_collection_initializer_style = chop_if_long +resharper_wrap_parameters_style = wrap_if_long +resharper_wrap_property_pattern = chop_if_long +resharper_wrap_switch_expression = chop_always +resharper_wrap_ternary_expr_style = chop_if_long +resharper_wrap_verbatim_interpolated_strings = no_wrap +resharper_xmldoc_attribute_indent = single_indent +resharper_xmldoc_attribute_style = do_not_touch +resharper_xmldoc_max_blank_lines_between_tags = 0 +resharper_xmldoc_pi_attribute_style = do_not_touch +resharper_xmldoc_space_before_self_closing = true +resharper_xmldoc_wrap_tags_and_pi = true +resharper_xmldoc_wrap_text = true + +# ReSharper inspection severities +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}] +indent_style = space +indent_size = 2 + +[{*.yaml,*.yml}] +indent_style = space +indent_size = 2 + +[*.{appxmanifest,asax,ascx,aspx,axaml,build,cg,cginc,compute,cs,cshtml,dtd,fx,fxh,hlsl,hlsli,hlslinc,master,nuspec,paml,razor,resw,resx,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}] +indent_style = space +indent_size = 4 +tab_width = 4 \ No newline at end of file diff --git a/source/RevitLookup/App.xaml b/source/RevitLookupObsolete/App.xaml similarity index 100% rename from source/RevitLookup/App.xaml rename to source/RevitLookupObsolete/App.xaml diff --git a/source/RevitLookupObsolete/Application.cs b/source/RevitLookupObsolete/Application.cs new file mode 100644 index 000000000..527141c3c --- /dev/null +++ b/source/RevitLookupObsolete/Application.cs @@ -0,0 +1,62 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Windows.Interop; +using System.Windows.Media; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Core; +using RevitLookup.Services.Contracts; + +namespace RevitLookup; + +[UsedImplicitly] +public class Application : ExternalApplication +{ + public override void OnStartup() + { + RevitShell.RegisterHandlers(); + Host.Start(); + + RibbonController.CreatePanel(Application); + } + + public override void OnShutdown() + { + Host.Stop(); + } + + public static void EnableHardwareRendering() + { + var settingsService = Host.GetService(); + if (!settingsService.GeneralSettings.UseHardwareRendering) return; + + //Revit overrides render mode during initialization + //EventHandler is called after initialization + RevitShell.ActionEventHandler.Raise(_ => RenderOptions.ProcessRenderMode = RenderMode.Default); + } + + public static void DisableHardwareRendering() + { + var settingsService = Host.GetService(); + if (settingsService.GeneralSettings.UseHardwareRendering) return; + + RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/DashboardCommand.cs b/source/RevitLookupObsolete/Commands/DashboardCommand.cs new file mode 100644 index 000000000..32b652674 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/DashboardCommand.cs @@ -0,0 +1,36 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class DashboardCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService().Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/EventMonitorCommand.cs b/source/RevitLookupObsolete/Commands/EventMonitorCommand.cs new file mode 100644 index 000000000..d111bb02a --- /dev/null +++ b/source/RevitLookupObsolete/Commands/EventMonitorCommand.cs @@ -0,0 +1,36 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class EventMonitorCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService().Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SearchElementsCommand.cs b/source/RevitLookupObsolete/Commands/SearchElementsCommand.cs new file mode 100644 index 000000000..2efa63aca --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SearchElementsCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.ViewModels.Contracts; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SearchElementsCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Show() + .Execute(dashboard => dashboard.OpenDialogCommand.Execute("search")); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopDatabaseCommand.cs b/source/RevitLookupObsolete/Commands/SnoopDatabaseCommand.cs new file mode 100644 index 000000000..fbfb1cdd5 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopDatabaseCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopDatabaseCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Database) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopDocumentCommand.cs b/source/RevitLookupObsolete/Commands/SnoopDocumentCommand.cs new file mode 100644 index 000000000..8318c2d2b --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopDocumentCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopDocumentCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Document) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Services/Contracts/ISoftwareUpdateService.cs b/source/RevitLookupObsolete/Commands/SnoopEdgeCommand.cs similarity index 69% rename from source/RevitLookup/Services/Contracts/ISoftwareUpdateService.cs rename to source/RevitLookupObsolete/Commands/SnoopEdgeCommand.cs index 1352655eb..26dab7757 100644 --- a/source/RevitLookup/Services/Contracts/ISoftwareUpdateService.cs +++ b/source/RevitLookupObsolete/Commands/SnoopEdgeCommand.cs @@ -18,19 +18,22 @@ // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) // (Rights in Technical Data and Computer Software), as applicable. +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; -namespace RevitLookup.Services.Contracts; +namespace RevitLookup.Commands; -public interface ISoftwareUpdateService +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopEdgeCommand : ExternalCommand { - public SoftwareUpdateState State { get; } - public string NewVersion { get; } - public string LatestCheckDate { get; } - public string ReleaseNotesUrl { get; } - public string ErrorMessage { get; } - public string LocalFilePath { get; } - - Task CheckUpdatesAsync(); - Task DownloadUpdate(); + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Edge) + .Show(); + } } \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopFaceCommand.cs b/source/RevitLookupObsolete/Commands/SnoopFaceCommand.cs new file mode 100644 index 000000000..9f388034c --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopFaceCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopFaceCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Face) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopLinkedElementCommand.cs b/source/RevitLookupObsolete/Commands/SnoopLinkedElementCommand.cs new file mode 100644 index 000000000..cfc625056 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopLinkedElementCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopLinkedElementCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.LinkedElement) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopPointCommand.cs b/source/RevitLookupObsolete/Commands/SnoopPointCommand.cs new file mode 100644 index 000000000..01a6bdd39 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopPointCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopPointCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Point) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopSelectionCommand.cs b/source/RevitLookupObsolete/Commands/SnoopSelectionCommand.cs new file mode 100644 index 000000000..b6ac45936 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopSelectionCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopSelectionCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.Selection) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopSubElementCommand.cs b/source/RevitLookupObsolete/Commands/SnoopSubElementCommand.cs new file mode 100644 index 000000000..72999de59 --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopSubElementCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopSubElementCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.SubElement) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookupObsolete/Commands/SnoopViewCommand.cs b/source/RevitLookupObsolete/Commands/SnoopViewCommand.cs new file mode 100644 index 000000000..695ca8eac --- /dev/null +++ b/source/RevitLookupObsolete/Commands/SnoopViewCommand.cs @@ -0,0 +1,39 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using Autodesk.Revit.Attributes; +using Nice3point.Revit.Toolkit.External; +using RevitLookup.Services.Contracts; +using RevitLookup.Services.Enums; +using RevitLookup.Views.Pages; + +namespace RevitLookup.Commands; + +[UsedImplicitly] +[Transaction(TransactionMode.Manual)] +public class SnoopViewCommand : ExternalCommand +{ + public override void Execute() + { + Host.GetService() + .Snoop(SnoopableType.View) + .Show(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Config/GeneralConfiguration.cs b/source/RevitLookupObsolete/Config/GeneralConfiguration.cs similarity index 100% rename from source/RevitLookup/Config/GeneralConfiguration.cs rename to source/RevitLookupObsolete/Config/GeneralConfiguration.cs diff --git a/source/RevitLookupObsolete/Config/LoggerConfigurator.cs b/source/RevitLookupObsolete/Config/LoggerConfigurator.cs new file mode 100644 index 000000000..b0f8edcb0 --- /dev/null +++ b/source/RevitLookupObsolete/Config/LoggerConfigurator.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Core; +using Serilog.Events; + +namespace RevitLookup.Config; + +public static class LoggerConfigurator +{ + private const string LogTemplate = "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] {SourceContext}: {Message:lj}{NewLine}{Exception}"; + + public static void AddSerilogConfiguration(this ILoggingBuilder builder) + { + var logger = CreateDefaultLogger(); + builder.AddSerilog(logger); + + AppDomain.CurrentDomain.UnhandledException += OnOnUnhandledException; + } + + private static Logger CreateDefaultLogger() + { + return new LoggerConfiguration() + .WriteTo.Console(LogEventLevel.Information, LogTemplate) + .WriteTo.Debug(LogEventLevel.Debug, LogTemplate) + .WriteTo.RevitJournal(Context.UiApplication, restrictedToMinimumLevel: LogEventLevel.Error, outputTemplate: LogTemplate) + .MinimumLevel.Debug() + .CreateLogger(); + } + + private static void OnOnUnhandledException(object sender, UnhandledExceptionEventArgs args) + { + var exception = (Exception) args.ExceptionObject; + var logger = Host.GetService>(); + logger.LogCritical(exception, "Domain unhandled exception"); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Config/OptionsConfiguration.cs b/source/RevitLookupObsolete/Config/OptionsConfiguration.cs similarity index 100% rename from source/RevitLookup/Config/OptionsConfiguration.cs rename to source/RevitLookupObsolete/Config/OptionsConfiguration.cs diff --git a/source/RevitLookup/Config/RenderConfiguration.cs b/source/RevitLookupObsolete/Config/RenderConfiguration.cs similarity index 100% rename from source/RevitLookup/Config/RenderConfiguration.cs rename to source/RevitLookupObsolete/Config/RenderConfiguration.cs diff --git a/source/RevitLookup/Core/ComponentModel/DescriptorMap.cs b/source/RevitLookupObsolete/Core/ComponentModel/DescriptorMap.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/DescriptorMap.cs rename to source/RevitLookupObsolete/Core/ComponentModel/DescriptorMap.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/APIObjectDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/APIObjectDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/APIObjectDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/APIObjectDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/AnalyticalLinkTypeDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AnalyticalLinkTypeDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/AnalyticalLinkTypeDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AnalyticalLinkTypeDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ApplicationDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ApplicationDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ApplicationDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ApplicationDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/AreaVolumeSettingsDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AreaVolumeSettingsDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/AreaVolumeSettingsDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AreaVolumeSettingsDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/AssetPropertiesDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AssetPropertiesDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/AssetPropertiesDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AssetPropertiesDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/AssetPropertyDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AssetPropertyDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/AssetPropertyDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/AssetPropertyDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/BasePointDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BasePointDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/BasePointDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BasePointDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/BoundarySegmentDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BoundarySegmentDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/BoundarySegmentDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BoundarySegmentDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/BoundingBoxXyzDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BoundingBoxXyzDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/BoundingBoxXyzDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/BoundingBoxXyzDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CategoryDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CategoryDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CategoryDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CategoryDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CityDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CityDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CityDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CityDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ColorDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ColorDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ColorDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ColorDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ColorMediaDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ColorMediaDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ColorMediaDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ColorMediaDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CompoundStructureLayerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CompoundStructureLayerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CompoundStructureLayerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CompoundStructureLayerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ConnectorManagerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ConnectorManagerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ConnectorManagerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ConnectorManagerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CurtainGridDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurtainGridDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CurtainGridDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurtainGridDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CurveDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurveDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CurveDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurveDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CurveElementDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurveElementDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CurveElementDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CurveElementDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/CylindricalFaceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CylindricalFaceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/CylindricalFaceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/CylindricalFaceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DatumPlaneDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DatumPlaneDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DatumPlaneDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DatumPlaneDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionBindingMapIteratorDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionGroupDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionGroupDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DefinitionGroupDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DefinitionGroupDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DependencyObjectDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DisposableDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DisposableDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DisposableDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DisposableDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/DocumentDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DocumentDescriptor.cs similarity index 96% rename from source/RevitLookup/Core/ComponentModel/Descriptors/DocumentDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DocumentDescriptor.cs index f19c1234a..e9f447493 100644 --- a/source/RevitLookup/Core/ComponentModel/Descriptors/DocumentDescriptor.cs +++ b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/DocumentDescriptor.cs @@ -23,6 +23,7 @@ #if REVIT2023_OR_GREATER using Autodesk.Revit.DB.Structure; #endif + #if !REVIT2025_OR_GREATER using Autodesk.Revit.DB.Macros; #endif @@ -32,13 +33,13 @@ namespace RevitLookup.Core.ComponentModel.Descriptors; public sealed class DocumentDescriptor : Descriptor, IDescriptorResolver, IDescriptorExtension { private readonly Document _document; - + public DocumentDescriptor(Document document) { _document = document; Name = document.Title; } - + public Func Resolve(Document context, string target, ParameterInfo[] parameters) { return target switch @@ -52,23 +53,24 @@ public Func Resolve(Document context, string target, ParameterInfo[] #endif _ => null }; - + IVariants ResolvePlanTopologies() { if (_document.IsReadOnly) return Variants.Empty(); - + var transaction = new Transaction(_document); transaction.Start("Calculating plan topologies"); var topologies = _document.PlanTopologies; transaction.Commit(); - + return Variants.Single(topologies); } + IVariants ResolveDefaultElementTypeId() { var values = Enum.GetValues(typeof(ElementTypeGroup)); var variants = new Variants(values.Length); - + foreach (ElementTypeGroup value in values) { var result = _document.GetDefaultElementTypeId(value); @@ -81,22 +83,23 @@ IVariants ResolveDefaultElementTypeId() variants.Add(result, $"{value.ToString()}: {result}"); } } - + return variants; } #if REVIT2024_OR_GREATER - + IVariants ResolveGetUnusedElements() { return Variants.Single(context.GetUnusedElements(new HashSet())); } - + IVariants ResolveGetAllUnusedElements() { return Variants.Single(context.GetAllUnusedElements(new HashSet())); } #endif } + public void RegisterExtensions(IExtensionManager manager) { manager.Register(nameof(GlobalParametersManager.GetAllGlobalParameters), GlobalParametersManager.GetAllGlobalParameters); @@ -113,14 +116,14 @@ public void RegisterExtensions(IExtensionManager manager) #endif if (_document.IsFamilyDocument) { - manager.Register(nameof(FamilySizeTableManager.GetFamilySizeTableManager), context => + manager.Register(nameof(FamilySizeTableManager.CreateFamilySizeTableManager), context => { var familyTableId = new ElementId(BuiltInParameter.RBS_LOOKUP_TABLE_NAME); return FamilySizeTableManager.GetFamilySizeTableManager(context, familyTableId); }); manager.Register(nameof(LightFamily.GetLightFamily), LightFamily.GetLightFamily); } - + // Disabled: slow performance. // manager.Register(nameof(WorksharingUtils.GetUserWorksetInfo), context => // { diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/EdgeDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EdgeDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/EdgeDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EdgeDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ElementDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElementDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ElementDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElementDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ElementIdDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElementIdDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ElementIdDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElementIdDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ElevationMarkerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElevationMarkerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ElevationMarkerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ElevationMarkerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/EntityDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EntityDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/EntityDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EntityDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/EnumerableDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EnumerableDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/EnumerableDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EnumerableDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EnumeratorDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/EvaluatedParameterDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EvaluatedParameterDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/EvaluatedParameterDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/EvaluatedParameterDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ExternalServiceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ExternalServiceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ExternalServiceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ExternalServiceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FaceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FaceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FaceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FaceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FailureMessageDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FailureMessageDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FailureMessageDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FailureMessageDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilyDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilyDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilyInstanceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyInstanceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilyInstanceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyInstanceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyManagerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilyParameterDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyParameterDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilyParameterDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilyParameterDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableColumnDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableColumnDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableColumnDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableColumnDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableManagerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableManagerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FamilySizeTableManagerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FamilySizeTableManagerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/FieldDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FieldDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/FieldDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/FieldDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ForgeTypeIdDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ForgeTypeIdDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ForgeTypeIdDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ForgeTypeIdDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/GuidEnumDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/GuidEnumDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/GuidEnumDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/GuidEnumDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/HostObjectDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/HostObjectDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/HostObjectDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/HostObjectDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/IndependentTagDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/IndependentTagDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/IndependentTagDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/IndependentTagDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/InternalOriginDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/InternalOriginDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/InternalOriginDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/InternalOriginDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/LightFamilyDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/LightFamilyDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/LightFamilyDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/LightFamilyDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/LocationCurveDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/LocationCurveDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/LocationCurveDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/LocationCurveDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/MacroManagerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MacroManagerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/MacroManagerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MacroManagerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/MepSectionDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MepSectionDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/MepSectionDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MepSectionDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/MepSystemDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MepSystemDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/MepSystemDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MepSystemDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/MeshDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MeshDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/MeshDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/MeshDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PanelDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PanelDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PanelDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PanelDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PaperSize.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PaperSize.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PaperSize.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PaperSize.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ParameterDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ParameterDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ParameterDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ParameterDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PartDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PartDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PartDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PartDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PartMakerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PartMakerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PartMakerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PartMakerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PerformanceAdviserDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PerformanceAdviserDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PerformanceAdviserDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PerformanceAdviserDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PipeDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PipeDescriptor.cs similarity index 90% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PipeDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PipeDescriptor.cs index ce950c464..69a345679 100644 --- a/source/RevitLookup/Core/ComponentModel/Descriptors/PipeDescriptor.cs +++ b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PipeDescriptor.cs @@ -27,10 +27,10 @@ public class PipeDescriptor(Pipe pipe) : ElementDescriptor(pipe) { public override void RegisterExtensions(IExtensionManager manager) { - manager.Register(nameof(PlumbingUtils.HasOpenConnector), _ => PlumbingUtils.HasOpenConnector(pipe.Document, pipe.Id)); + manager.Register(nameof(PlumbingUtils.PlaceCapOnOpenEnds), _ => PlumbingUtils.HasOpenConnector(pipe.Document, pipe.Id)); } - - + + public override Func Resolve(Document context, string target, ParameterInfo[] parameters) { return null; diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PlanViewRangeDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PlanViewRangeDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PlanViewRangeDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PlanViewRangeDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/PrintManagerDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PrintManagerDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/PrintManagerDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/PrintManagerDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ReferenceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/RevisionNumberingSequenceDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RevisionNumberingSequenceDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/RevisionNumberingSequenceDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RevisionNumberingSequenceDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/RevitLinkTypeDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RevitLinkTypeDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/RevitLinkTypeDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RevitLinkTypeDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/RibbonItemDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonItemDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/RibbonItemDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonItemDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/RibbonPanelDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonPanelDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/RibbonPanelDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonPanelDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/RibbonTabDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonTabDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/RibbonTabDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/RibbonTabDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/SchedulableFieldDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SchedulableFieldDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/SchedulableFieldDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SchedulableFieldDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ScheduleDefinitionDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ScheduleDefinitionDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ScheduleDefinitionDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ScheduleDefinitionDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/SchemaDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SchemaDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/SchemaDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SchemaDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/SolidDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SolidDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/SolidDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SolidDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/SpatialElementDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SpatialElementDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/SpatialElementDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SpatialElementDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/StringDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/StringDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/StringDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/StructuralSettingsDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/StructuralSettingsDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/StructuralSettingsDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/StructuralSettingsDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/SunAndShadowSettingsDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SunAndShadowSettingsDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/SunAndShadowSettingsDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/SunAndShadowSettingsDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/TableDataDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableDataDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/TableDataDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableDataDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/TableSectionDataDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableSectionDataDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/TableSectionDataDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableSectionDataDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/TableViewDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableViewDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/TableViewDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/TableViewDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/UiApplicationDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiApplicationDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/UiApplicationDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiApplicationDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/UiElementDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiElementDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/UiElementDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiElementDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UiObjectDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/UpdaterInfoDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UpdaterInfoDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/UpdaterInfoDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/UpdaterInfoDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/VariantDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/VariantDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/VariantDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/VariantDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/VariantsDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/VariantsDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/VariantsDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/VariantsDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ViewDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ViewDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ViewDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ViewDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/ViewScheduleDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ViewScheduleDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/ViewScheduleDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/ViewScheduleDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/WireDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WireDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/WireDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WireDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/WorksetDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WorksetDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/WorksetDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WorksetDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/WorksetTableDescriptor.cs diff --git a/source/RevitLookup/Core/ComponentModel/Descriptors/XyzDescriptor.cs b/source/RevitLookupObsolete/Core/ComponentModel/Descriptors/XyzDescriptor.cs similarity index 100% rename from source/RevitLookup/Core/ComponentModel/Descriptors/XyzDescriptor.cs rename to source/RevitLookupObsolete/Core/ComponentModel/Descriptors/XyzDescriptor.cs diff --git a/source/RevitLookup/Core/Enums/SearchOption.cs b/source/RevitLookupObsolete/Core/Enums/SearchOption.cs similarity index 100% rename from source/RevitLookup/Core/Enums/SearchOption.cs rename to source/RevitLookupObsolete/Core/Enums/SearchOption.cs diff --git a/source/RevitLookup/Core/Modules/Configuration/RevitConfigurator.cs b/source/RevitLookupObsolete/Core/Modules/Configuration/RevitConfigurator.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Configuration/RevitConfigurator.cs rename to source/RevitLookupObsolete/Core/Modules/Configuration/RevitConfigurator.cs diff --git a/source/RevitLookup/Core/Modules/Events/EventMonitor.cs b/source/RevitLookupObsolete/Core/Modules/Events/EventMonitor.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Events/EventMonitor.cs rename to source/RevitLookupObsolete/Core/Modules/Events/EventMonitor.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/BoundingBoxVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/BoundingBoxVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/BoundingBoxVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/BoundingBoxVisualizationServer.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/FaceVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/FaceVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/FaceVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/FaceVisualizationServer.cs diff --git a/source/RevitLookupObsolete/Core/Modules/Visualization/Helpers/RenderGeometryHelper.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/Helpers/RenderGeometryHelper.cs new file mode 100644 index 000000000..8076d6981 --- /dev/null +++ b/source/RevitLookupObsolete/Core/Modules/Visualization/Helpers/RenderGeometryHelper.cs @@ -0,0 +1,231 @@ +// Copyright 2003-2024 by Autodesk, Inc. +// +// Permission to use, copy, modify, and distribute this software in +// object code form for any purpose and without fee is hereby granted, +// provided that the above copyright notice appears in all copies and +// that both that copyright notice and the limited warranty and +// restricted rights notice below appear in all supporting +// documentation. +// +// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. +// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF +// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. +// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE +// UNINTERRUPTED OR ERROR FREE. +// +// Use, duplication, or disclosure by the U.S. Government is subject to +// restrictions set forth in FAR 52.227-19 (Commercial Computer +// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) +// (Rights in Technical Data and Computer Software), as applicable. + +using System.Diagnostics.CodeAnalysis; + +namespace RevitLookup.Core.Visualization.Helpers; + +public static class RenderGeometryHelper +{ + public static List> GetSegmentationTube(IList vertices, double diameter) + { + var points = new List>(); + + for (var i = 0; i < vertices.Count; i++) + { + var center = vertices[i]; + XYZ normal; + if (i == 0) + { + normal = (vertices[i + 1] - center).Normalize(); + } + else if (i == vertices.Count - 1) + { + normal = (center - vertices[i - 1]).Normalize(); + } + else + { + normal = ((vertices[i + 1] - vertices[i - 1]) / 2.0).Normalize(); + } + + points.Add(TessellateCircle(center, normal, diameter / 2)); + } + + return points; + } + + public static XYZ GetMeshVertexNormal(Mesh mesh, int index, DistributionOfNormals normalDistribution) + { + switch (normalDistribution) + { + case DistributionOfNormals.AtEachPoint: + return mesh.GetNormal(index); + case DistributionOfNormals.OnEachFacet: + var vertex = mesh.Vertices[index]; + for (var i = 0; i < mesh.NumTriangles; i++) + { + var triangle = mesh.get_Triangle(i); + var triangleVertex = triangle.get_Vertex(0); + if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i); + triangleVertex = triangle.get_Vertex(1); + if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i); + triangleVertex = triangle.get_Vertex(2); + if (triangleVertex.IsAlmostEqualTo(vertex)) return mesh.GetNormal(i); + } + + return XYZ.Zero; + case DistributionOfNormals.OnePerFace: + return mesh.GetNormal(0); + default: + throw new ArgumentOutOfRangeException(nameof(normalDistribution), normalDistribution, null); + } + } + + public static List TessellateCircle(XYZ center, XYZ normal, double radius) + { + var vertices = new List(); + var segmentCount = InterpolateSegmentsCount(radius); + var xDirection = normal.CrossProduct(XYZ.BasisZ).Normalize() * radius; + if (xDirection.IsZeroLength()) + { + xDirection = normal.CrossProduct(XYZ.BasisX).Normalize() * radius; + } + + var yDirection = normal.CrossProduct(xDirection).Normalize() * radius; + + for (var i = 0; i < segmentCount; i++) + { + var angle = 2 * Math.PI * i / segmentCount; + var vertex = center + xDirection * Math.Cos(angle) + yDirection * Math.Sin(angle); + vertices.Add(vertex); + } + + return vertices; + } + + public static Solid ScaleSolid(Solid solid, double scale) + { + if (scale is 1) scale = EvaluateScale(solid, Context.Application.VertexTolerance * 3); + + var centroid = solid.GetBoundingBox().Transform.Origin; + var moveToCentroid = Transform.CreateTranslation(-centroid); + var scaleTransform = Transform.Identity.ScaleBasis(scale); + var moveBack = Transform.CreateTranslation(centroid); + var combinedTransform = moveBack.Multiply(scaleTransform).Multiply(moveToCentroid); + return SolidUtils.CreateTransformed(solid, combinedTransform); + } + + public static int InterpolateSegmentsCount(double diameter) + { + const int minSegments = 6; + const int maxSegments = 33; + const double minDiameter = 0.1 / 12d; + const double maxDiameter = 3 / 12d; + + if (diameter <= minDiameter) return minSegments; + if (diameter >= maxDiameter) return maxSegments; + + var normalDiameter = (diameter - minDiameter) / (maxDiameter - minDiameter); + return (int) (minSegments + normalDiameter * (maxSegments - minSegments)); + } + + public static double InterpolateOffsetByDiameter(double diameter) + { + const double minOffset = 0.01d; + const double maxOffset = 0.1d; + const double minDiameter = 0.1 / 12d; + const double maxDiameter = 3 / 12d; + + if (diameter <= minDiameter) return minOffset; + if (diameter >= maxDiameter) return maxOffset; + + var normalOffset = (diameter - minDiameter) / (maxDiameter - minDiameter); + return minOffset + normalOffset * (maxOffset - minOffset); + } + + public static double InterpolateOffsetByArea(double area) + { + const double minOffset = 0.01d; + const double maxOffset = 0.1d; + const double minArea = 0.01d; + const double maxArea = 1d; + + if (area <= minArea) return minOffset; + if (area >= maxArea) return maxOffset; + + var normalOffset = (area - minArea) / (maxArea - minArea); + return minOffset + normalOffset * (maxOffset - minOffset); + } + + public static double InterpolateAxisLengthByArea(double area) + { + const double minLength = 0.1d; + const double maxLength = 1d; + const double minArea = 0.01d; + const double maxArea = 1d; + + if (area <= minArea) return minLength; + if (area >= maxArea) return maxLength; + + var normalOffset = (area - minArea) / (maxArea - minArea); + return minLength + normalOffset * (maxLength - minLength); + } + + public static double InterpolateAxisLengthByPoints(XYZ min, XYZ max) + { + const double maxLength = 1d; + + var width = max.X - min.X; + var height = max.Y - min.Y; + var depth = max.Z - min.Z; + + var maxSize = Math.Max(width, Math.Max(height, depth)); + + if (maxLength * 2 < maxSize) + { + return maxLength; + } + + return maxSize * 0.35; + } + + public static double ComputeMeshSurfaceArea(Mesh mesh) + { +#if REVIT2024_OR_GREATER + return mesh.ComputeSurfaceArea(); +#else + var surfaceArea = 0.0; + + for (var i = 0; i < mesh.NumTriangles; i++) + { + var triangle = mesh.get_Triangle(i); + + var vertex0 = triangle.get_Vertex(0); + var vertex1 = triangle.get_Vertex(1); + var vertex2 = triangle.get_Vertex(2); + + var side1 = vertex1 - vertex0; + var side2 = vertex2 - vertex0; + + var crossProduct = side1.CrossProduct(side2); + + surfaceArea += crossProduct.GetLength() / 2.0; + } + + return surfaceArea; +#endif + } + + [SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator")] + private static double EvaluateScale(Solid solid, double offset) + { + var boundingBox = solid.GetBoundingBox(); + + var currentLength = boundingBox.Max.X - boundingBox.Min.X; + var currentWidth = boundingBox.Max.Y - boundingBox.Min.Y; + var currentHeight = boundingBox.Max.Z - boundingBox.Min.Z; + + var maxDimension = Math.Max(Math.Max(currentLength, currentWidth), currentHeight); + + if (maxDimension == currentLength) return (currentLength + offset) / currentLength; + if (maxDimension == currentWidth) return (currentWidth + offset) / currentWidth; + return (currentHeight + offset) / currentHeight; + } +} \ No newline at end of file diff --git a/source/RevitLookup/Core/Modules/Visualization/Helpers/RenderHelper.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/Helpers/RenderHelper.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/Helpers/RenderHelper.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/Helpers/RenderHelper.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/MeshVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/MeshVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/MeshVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/MeshVisualizationServer.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/PolylineVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/PolylineVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/PolylineVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/PolylineVisualizationServer.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/SolidVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/SolidVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/SolidVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/SolidVisualizationServer.cs diff --git a/source/RevitLookup/Core/Modules/Visualization/XyzVisualizationServer.cs b/source/RevitLookupObsolete/Core/Modules/Visualization/XyzVisualizationServer.cs similarity index 100% rename from source/RevitLookup/Core/Modules/Visualization/XyzVisualizationServer.cs rename to source/RevitLookupObsolete/Core/Modules/Visualization/XyzVisualizationServer.cs diff --git a/source/RevitLookup/Core/RevitShell.cs b/source/RevitLookupObsolete/Core/RevitShell.cs similarity index 100% rename from source/RevitLookup/Core/RevitShell.cs rename to source/RevitLookupObsolete/Core/RevitShell.cs diff --git a/source/RevitLookup/Core/Utils/ContextUtils.cs b/source/RevitLookupObsolete/Core/Utils/ContextUtils.cs similarity index 100% rename from source/RevitLookup/Core/Utils/ContextUtils.cs rename to source/RevitLookupObsolete/Core/Utils/ContextUtils.cs diff --git a/source/RevitLookupObsolete/Host.cs b/source/RevitLookupObsolete/Host.cs new file mode 100644 index 000000000..875b6d222 --- /dev/null +++ b/source/RevitLookupObsolete/Host.cs @@ -0,0 +1,136 @@ +using System.IO; +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using RevitLookup.Config; +using RevitLookup.Services; +using RevitLookup.Services.Contracts; +using RevitLookup.ViewModels.Contracts; +using RevitLookup.ViewModels.Dialogs; +using RevitLookup.ViewModels.Dialogs.Visualization; +using RevitLookup.ViewModels.Pages; +using RevitLookup.Views; +using RevitLookup.Views.Dialogs; +using RevitLookup.Views.Dialogs.Visualization; +using RevitLookup.Views.Pages; +using Wpf.Ui; + +namespace RevitLookup; + +/// +/// Provides a host for the application's services and manages their lifetimes +/// +public static class Host +{ + private static IHost _host; + + /// + /// Starts the host and configures the application's services + /// + public static void Start() + { + var builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(new HostApplicationBuilderSettings + { + ContentRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly()!.Location), + DisableDefaults = true + }); + + //Logging + builder.Logging.ClearProviders(); + builder.Logging.AddSerilogConfiguration(); + + //Configuration + builder.Services.AddOptions(builder.Configuration); + + //Application services + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddHostedService(); + + //UI services + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + //Views + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddTransient(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + + //Dialogs + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + builder.Services.AddTransient(); + + //Startup view + builder.Services.AddTransient(); + + _host = builder.Build(); + _host.Start(); + } + + /// + /// Starts the host proxy and configures the application's services + /// + public static void StartProxy(IHost host) + { + _host = host; + host.Start(); + } + + /// + /// Stops the host and handle services + /// + public static void Stop() + { + _host.StopAsync().GetAwaiter().GetResult(); + } + + /// + /// Get service of type + /// + /// The type of service object to get + /// There is no service of type + public static T GetService() where T : class + { + return _host.Services.GetRequiredService(); + } +} \ No newline at end of file diff --git a/source/RevitLookup/Models/GitHubResponse.cs b/source/RevitLookupObsolete/Models/GitHubResponse.cs similarity index 100% rename from source/RevitLookup/Models/GitHubResponse.cs rename to source/RevitLookupObsolete/Models/GitHubResponse.cs diff --git a/source/RevitLookup/Models/OpenSourceSoftware.cs b/source/RevitLookupObsolete/Models/OpenSourceSoftware.cs similarity index 100% rename from source/RevitLookup/Models/OpenSourceSoftware.cs rename to source/RevitLookupObsolete/Models/OpenSourceSoftware.cs diff --git a/source/RevitLookup/Models/Options/AssemblyInfo.cs b/source/RevitLookupObsolete/Models/Options/AssemblyInfo.cs similarity index 100% rename from source/RevitLookup/Models/Options/AssemblyInfo.cs rename to source/RevitLookupObsolete/Models/Options/AssemblyInfo.cs diff --git a/source/RevitLookup/Models/Options/FolderLocations.cs b/source/RevitLookupObsolete/Models/Options/FolderLocations.cs similarity index 100% rename from source/RevitLookup/Models/Options/FolderLocations.cs rename to source/RevitLookupObsolete/Models/Options/FolderLocations.cs diff --git a/source/RevitLookup/Models/Render/RenderFailedEventArgs.cs b/source/RevitLookupObsolete/Models/Render/RenderFailedEventArgs.cs similarity index 100% rename from source/RevitLookup/Models/Render/RenderFailedEventArgs.cs rename to source/RevitLookupObsolete/Models/Render/RenderFailedEventArgs.cs diff --git a/source/RevitLookup/Models/Render/RenderingBufferStorage.cs b/source/RevitLookupObsolete/Models/Render/RenderingBufferStorage.cs similarity index 100% rename from source/RevitLookup/Models/Render/RenderingBufferStorage.cs rename to source/RevitLookupObsolete/Models/Render/RenderingBufferStorage.cs diff --git a/source/RevitLookup/Models/Settings/GeneralSettings.cs b/source/RevitLookupObsolete/Models/Settings/GeneralSettings.cs similarity index 100% rename from source/RevitLookup/Models/Settings/GeneralSettings.cs rename to source/RevitLookupObsolete/Models/Settings/GeneralSettings.cs diff --git a/source/RevitLookup/Models/Settings/RenderSettings.cs b/source/RevitLookupObsolete/Models/Settings/RenderSettings.cs similarity index 100% rename from source/RevitLookup/Models/Settings/RenderSettings.cs rename to source/RevitLookupObsolete/Models/Settings/RenderSettings.cs diff --git a/source/RevitLookup/Models/UnitInfo.cs b/source/RevitLookupObsolete/Models/UnitInfo.cs similarity index 100% rename from source/RevitLookup/Models/UnitInfo.cs rename to source/RevitLookupObsolete/Models/UnitInfo.cs diff --git a/source/RevitLookupObsolete/Resources/Images/RibbonIcon16.png b/source/RevitLookupObsolete/Resources/Images/RibbonIcon16.png new file mode 100644 index 000000000..841e758cd Binary files /dev/null and b/source/RevitLookupObsolete/Resources/Images/RibbonIcon16.png differ diff --git a/source/RevitLookupObsolete/Resources/Images/RibbonIcon32.png b/source/RevitLookupObsolete/Resources/Images/RibbonIcon32.png new file mode 100644 index 000000000..2481656a0 Binary files /dev/null and b/source/RevitLookupObsolete/Resources/Images/RibbonIcon32.png differ diff --git a/source/RevitLookup/Resources/Localization/Colors.Designer.cs b/source/RevitLookupObsolete/Resources/Localization/Colors.Designer.cs similarity index 100% rename from source/RevitLookup/Resources/Localization/Colors.Designer.cs rename to source/RevitLookupObsolete/Resources/Localization/Colors.Designer.cs diff --git a/source/RevitLookup/Resources/Localization/Colors.resx b/source/RevitLookupObsolete/Resources/Localization/Colors.resx similarity index 100% rename from source/RevitLookup/Resources/Localization/Colors.resx rename to source/RevitLookupObsolete/Resources/Localization/Colors.resx diff --git a/source/RevitLookup/Resources/Localization/Colors.ru.resx b/source/RevitLookupObsolete/Resources/Localization/Colors.ru.resx similarity index 100% rename from source/RevitLookup/Resources/Localization/Colors.ru.resx rename to source/RevitLookupObsolete/Resources/Localization/Colors.ru.resx diff --git a/source/RevitLookupObsolete/RevitLookup.addin b/source/RevitLookupObsolete/RevitLookup.addin new file mode 100644 index 000000000..ad47572a5 --- /dev/null +++ b/source/RevitLookupObsolete/RevitLookup.addin @@ -0,0 +1,10 @@ + + + RevitLookup + RevitLookup/RevitLookup.dll + RevitLookup.Application + 356CDA5A-E6C5-4c2f-A9EF-B3222116B8C8 + ADSK + Autodesk, www.autodesk.com + + diff --git a/source/RevitLookupObsolete/RevitLookupObsolete.csproj b/source/RevitLookupObsolete/RevitLookupObsolete.csproj new file mode 100644 index 000000000..b6aedea2e --- /dev/null +++ b/source/RevitLookupObsolete/RevitLookupObsolete.csproj @@ -0,0 +1,121 @@ + + + + true + CS8826 + disable + latest + x64 + true + true + Debug R21;Debug R22;Debug R23;Debug R24;Debug R25 + $(Configurations);Release R21;Release R22;Release R23;Release R24;Release R25 + RevitLookup + + + + 2021 + net48 + + + 2022 + net48 + + + 2023 + net48 + + + 2024 + net48 + + + 2025 + net8.0-windows + + + + Program + C:\Program Files\Autodesk\Revit $(RevitVersion)\Revit.exe + /language ENG + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ResXFileCodeGenerator + Colors.Designer.cs + + + ResXFileCodeGenerator + Colors.Designer.cs + PublicResXFileCodeGenerator + + + + + + True + True + Colors.resx + + + True + True + Colors.resx + + + + diff --git a/source/RevitLookupObsolete/RevitLookupObsolete.csproj.DotSettings b/source/RevitLookupObsolete/RevitLookupObsolete.csproj.DotSettings new file mode 100644 index 000000000..7057a74b6 --- /dev/null +++ b/source/RevitLookupObsolete/RevitLookupObsolete.csproj.DotSettings @@ -0,0 +1,5 @@ + + No \ No newline at end of file diff --git a/source/RevitLookup/RibbonController.cs b/source/RevitLookupObsolete/RibbonController.cs similarity index 100% rename from source/RevitLookup/RibbonController.cs rename to source/RevitLookupObsolete/RibbonController.cs diff --git a/source/RevitLookup/Services/Contracts/ILookupService.cs b/source/RevitLookupObsolete/Services/Contracts/ILookupService.cs similarity index 100% rename from source/RevitLookup/Services/Contracts/ILookupService.cs rename to source/RevitLookupObsolete/Services/Contracts/ILookupService.cs diff --git a/source/RevitLookup/Services/Contracts/ISettings.cs b/source/RevitLookupObsolete/Services/Contracts/ISettings.cs similarity index 100% rename from source/RevitLookup/Services/Contracts/ISettings.cs rename to source/RevitLookupObsolete/Services/Contracts/ISettings.cs diff --git a/source/RevitLookup/Services/Contracts/ISettingsService.cs b/source/RevitLookupObsolete/Services/Contracts/ISettingsService.cs similarity index 100% rename from source/RevitLookup/Services/Contracts/ISettingsService.cs rename to source/RevitLookupObsolete/Services/Contracts/ISettingsService.cs diff --git a/source/RevitLookup/Services/Contracts/ISnoopVisualService.cs b/source/RevitLookupObsolete/Services/Contracts/ISnoopVisualService.cs similarity index 100% rename from source/RevitLookup/Services/Contracts/ISnoopVisualService.cs rename to source/RevitLookupObsolete/Services/Contracts/ISnoopVisualService.cs diff --git a/source/RevitLookup/Services/Contracts/IWindow.cs b/source/RevitLookupObsolete/Services/Contracts/IWindow.cs similarity index 100% rename from source/RevitLookup/Services/Contracts/IWindow.cs rename to source/RevitLookupObsolete/Services/Contracts/IWindow.cs diff --git a/source/RevitLookup/Services/Enums/SnoopableType.cs b/source/RevitLookupObsolete/Services/Enums/SnoopableType.cs similarity index 100% rename from source/RevitLookup/Services/Enums/SnoopableType.cs rename to source/RevitLookupObsolete/Services/Enums/SnoopableType.cs diff --git a/source/RevitLookup/Services/HostedLifecycleService.cs b/source/RevitLookupObsolete/Services/HostedLifecycleService.cs similarity index 100% rename from source/RevitLookup/Services/HostedLifecycleService.cs rename to source/RevitLookupObsolete/Services/HostedLifecycleService.cs diff --git a/source/RevitLookup/Services/LookupService.cs b/source/RevitLookupObsolete/Services/LookupService.cs similarity index 100% rename from source/RevitLookup/Services/LookupService.cs rename to source/RevitLookupObsolete/Services/LookupService.cs diff --git a/source/RevitLookup/Services/SettingsService.cs b/source/RevitLookupObsolete/Services/SettingsService.cs similarity index 100% rename from source/RevitLookup/Services/SettingsService.cs rename to source/RevitLookupObsolete/Services/SettingsService.cs diff --git a/source/RevitLookup/Services/SnoopVisualService.cs b/source/RevitLookupObsolete/Services/SnoopVisualService.cs similarity index 100% rename from source/RevitLookup/Services/SnoopVisualService.cs rename to source/RevitLookupObsolete/Services/SnoopVisualService.cs diff --git a/source/RevitLookup/Services/SoftwareUpdateService.cs b/source/RevitLookupObsolete/Services/SoftwareUpdateService.cs similarity index 100% rename from source/RevitLookup/Services/SoftwareUpdateService.cs rename to source/RevitLookupObsolete/Services/SoftwareUpdateService.cs diff --git a/source/RevitLookup/Utils/AccessUtils.cs b/source/RevitLookupObsolete/Utils/AccessUtils.cs similarity index 100% rename from source/RevitLookup/Utils/AccessUtils.cs rename to source/RevitLookupObsolete/Utils/AccessUtils.cs diff --git a/source/RevitLookup/Utils/ColorFormatUtils.cs b/source/RevitLookupObsolete/Utils/ColorFormatUtils.cs similarity index 100% rename from source/RevitLookup/Utils/ColorFormatUtils.cs rename to source/RevitLookupObsolete/Utils/ColorFormatUtils.cs diff --git a/source/RevitLookup/Utils/ColorRepresentationUtils.cs b/source/RevitLookupObsolete/Utils/ColorRepresentationUtils.cs similarity index 100% rename from source/RevitLookup/Utils/ColorRepresentationUtils.cs rename to source/RevitLookupObsolete/Utils/ColorRepresentationUtils.cs diff --git a/source/RevitLookup/Utils/ProcessTasks.cs b/source/RevitLookupObsolete/Utils/ProcessTasks.cs similarity index 100% rename from source/RevitLookup/Utils/ProcessTasks.cs rename to source/RevitLookupObsolete/Utils/ProcessTasks.cs diff --git a/source/RevitLookup/Utils/RibbonUtils.cs b/source/RevitLookupObsolete/Utils/RibbonUtils.cs similarity index 100% rename from source/RevitLookup/Utils/RibbonUtils.cs rename to source/RevitLookupObsolete/Utils/RibbonUtils.cs diff --git a/source/RevitLookup/Utils/TypeExtensions.cs b/source/RevitLookupObsolete/Utils/TypeExtensions.cs similarity index 100% rename from source/RevitLookup/Utils/TypeExtensions.cs rename to source/RevitLookupObsolete/Utils/TypeExtensions.cs diff --git a/source/RevitLookup/ViewModels/Contracts/IDashboardViewModel.cs b/source/RevitLookupObsolete/ViewModels/Contracts/IDashboardViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Contracts/IDashboardViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Contracts/IDashboardViewModel.cs diff --git a/source/RevitLookup/ViewModels/Contracts/IEventsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Contracts/IEventsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Contracts/IEventsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Contracts/IEventsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs b/source/RevitLookupObsolete/ViewModels/Contracts/ISnoopViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Contracts/ISnoopViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Contracts/ISnoopViewModel.cs diff --git a/source/RevitLookup/ViewModels/Converters/BooleanVisibilityConverter.cs b/source/RevitLookupObsolete/ViewModels/Converters/BooleanVisibilityConverter.cs similarity index 100% rename from source/RevitLookup/ViewModels/Converters/BooleanVisibilityConverter.cs rename to source/RevitLookupObsolete/ViewModels/Converters/BooleanVisibilityConverter.cs diff --git a/source/RevitLookup/ViewModels/Converters/InverseBooleanConverter.cs b/source/RevitLookupObsolete/ViewModels/Converters/InverseBooleanConverter.cs similarity index 100% rename from source/RevitLookup/ViewModels/Converters/InverseBooleanConverter.cs rename to source/RevitLookupObsolete/ViewModels/Converters/InverseBooleanConverter.cs diff --git a/source/RevitLookup/ViewModels/Converters/InverseBooleanVisibilityConverter.cs b/source/RevitLookupObsolete/ViewModels/Converters/InverseBooleanVisibilityConverter.cs similarity index 100% rename from source/RevitLookup/ViewModels/Converters/InverseBooleanVisibilityConverter.cs rename to source/RevitLookupObsolete/ViewModels/Converters/InverseBooleanVisibilityConverter.cs diff --git a/source/RevitLookup/ViewModels/Converters/UpdateConverter.cs b/source/RevitLookupObsolete/ViewModels/Converters/UpdateConverter.cs similarity index 100% rename from source/RevitLookup/ViewModels/Converters/UpdateConverter.cs rename to source/RevitLookupObsolete/ViewModels/Converters/UpdateConverter.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/EditParameterViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/EditParameterViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/EditParameterViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/EditParameterViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/FamilySizeTableEditDialogViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/FamilySizeTableEditDialogViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/FamilySizeTableEditDialogViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/FamilySizeTableEditDialogViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/FamilySizeTableSelectDialogViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/FamilySizeTableSelectDialogViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/FamilySizeTableSelectDialogViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/FamilySizeTableSelectDialogViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/ModulesViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/ModulesViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/ModulesViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/ModulesViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/OpenSourceViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/OpenSourceViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/OpenSourceViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/OpenSourceViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/SearchElementsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/SearchElementsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/SearchElementsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/UnitsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/UnitsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/UnitsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/UnitsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/BoundingBoxVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/BoundingBoxVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/BoundingBoxVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/BoundingBoxVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/FaceVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/FaceVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/FaceVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/FaceVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/MeshVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/MeshVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/MeshVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/MeshVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/PolylineVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/PolylineVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/PolylineVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/PolylineVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/SolidVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/SolidVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/SolidVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/SolidVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/Dialogs/Visualization/XyzVisualizationViewModel.cs b/source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/XyzVisualizationViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Dialogs/Visualization/XyzVisualizationViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Dialogs/Visualization/XyzVisualizationViewModel.cs diff --git a/source/RevitLookup/ViewModels/ObservableObjects/ObservableRevitSettingsEntry.cs b/source/RevitLookupObsolete/ViewModels/ObservableObjects/ObservableRevitSettingsEntry.cs similarity index 100% rename from source/RevitLookup/ViewModels/ObservableObjects/ObservableRevitSettingsEntry.cs rename to source/RevitLookupObsolete/ViewModels/ObservableObjects/ObservableRevitSettingsEntry.cs diff --git a/source/RevitLookup/ViewModels/Pages/AboutViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/AboutViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/AboutViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/AboutViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/DashboardViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/DashboardViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/DashboardViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/DashboardViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/EventsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/EventsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/EventsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/EventsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/RevitSettingsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/RevitSettingsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/RevitSettingsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/RevitSettingsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/SettingsViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/SettingsViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/SettingsViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/SettingsViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/SnoopViewModel.cs b/source/RevitLookupObsolete/ViewModels/Pages/SnoopViewModel.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/SnoopViewModel.cs rename to source/RevitLookupObsolete/ViewModels/Pages/SnoopViewModel.cs diff --git a/source/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs b/source/RevitLookupObsolete/ViewModels/Pages/SnoopViewModelBase.cs similarity index 100% rename from source/RevitLookup/ViewModels/Pages/SnoopViewModelBase.cs rename to source/RevitLookupObsolete/ViewModels/Pages/SnoopViewModelBase.cs diff --git a/source/RevitLookup/ViewModels/Utils/SearchEngine.cs b/source/RevitLookupObsolete/ViewModels/Utils/SearchEngine.cs similarity index 100% rename from source/RevitLookup/ViewModels/Utils/SearchEngine.cs rename to source/RevitLookupObsolete/ViewModels/Utils/SearchEngine.cs diff --git a/source/RevitLookup/Views/Appearance/RevitThemeWatcher.cs b/source/RevitLookupObsolete/Views/Appearance/RevitThemeWatcher.cs similarity index 100% rename from source/RevitLookup/Views/Appearance/RevitThemeWatcher.cs rename to source/RevitLookupObsolete/Views/Appearance/RevitThemeWatcher.cs diff --git a/source/RevitLookup/Views/Controls/DataGrid/DataGridCellTemplate.xaml b/source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridCellTemplate.xaml similarity index 100% rename from source/RevitLookup/Views/Controls/DataGrid/DataGridCellTemplate.xaml rename to source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridCellTemplate.xaml diff --git a/source/RevitLookup/Views/Controls/DataGrid/DataGridGroupStyle.xaml b/source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridGroupStyle.xaml similarity index 100% rename from source/RevitLookup/Views/Controls/DataGrid/DataGridGroupStyle.xaml rename to source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridGroupStyle.xaml diff --git a/source/RevitLookup/Views/Controls/DataGrid/DataGridGroupStyle.xaml.cs b/source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridGroupStyle.xaml.cs similarity index 100% rename from source/RevitLookup/Views/Controls/DataGrid/DataGridGroupStyle.xaml.cs rename to source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridGroupStyle.xaml.cs diff --git a/source/RevitLookup/Views/Controls/DataGrid/DataGridRowStyle.xaml b/source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridRowStyle.xaml similarity index 100% rename from source/RevitLookup/Views/Controls/DataGrid/DataGridRowStyle.xaml rename to source/RevitLookupObsolete/Views/Controls/DataGrid/DataGridRowStyle.xaml diff --git a/source/RevitLookup/Views/Controls/TreeView/TreeViewItemTemplate.xaml b/source/RevitLookupObsolete/Views/Controls/TreeView/TreeViewItemTemplate.xaml similarity index 100% rename from source/RevitLookup/Views/Controls/TreeView/TreeViewItemTemplate.xaml rename to source/RevitLookupObsolete/Views/Controls/TreeView/TreeViewItemTemplate.xaml diff --git a/source/RevitLookup/Views/Converters/BytesToStringConverter.cs b/source/RevitLookupObsolete/Views/Converters/BytesToStringConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/BytesToStringConverter.cs rename to source/RevitLookupObsolete/Views/Converters/BytesToStringConverter.cs diff --git a/source/RevitLookup/Views/Converters/CollectionEmptyAfterInitializationConverter.cs b/source/RevitLookupObsolete/Views/Converters/CollectionEmptyAfterInitializationConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/CollectionEmptyAfterInitializationConverter.cs rename to source/RevitLookupObsolete/Views/Converters/CollectionEmptyAfterInitializationConverter.cs diff --git a/source/RevitLookup/Views/Converters/CollectionEmptyVisibilityConverter.cs b/source/RevitLookupObsolete/Views/Converters/CollectionEmptyVisibilityConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/CollectionEmptyVisibilityConverter.cs rename to source/RevitLookupObsolete/Views/Converters/CollectionEmptyVisibilityConverter.cs diff --git a/source/RevitLookup/Views/Converters/DescriptorLabelConverters.cs b/source/RevitLookupObsolete/Views/Converters/DescriptorLabelConverters.cs similarity index 100% rename from source/RevitLookup/Views/Converters/DescriptorLabelConverters.cs rename to source/RevitLookupObsolete/Views/Converters/DescriptorLabelConverters.cs diff --git a/source/RevitLookup/Views/Converters/EmptySearchResultsVisibilityConverter.cs b/source/RevitLookupObsolete/Views/Converters/EmptySearchResultsVisibilityConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/EmptySearchResultsVisibilityConverter.cs rename to source/RevitLookupObsolete/Views/Converters/EmptySearchResultsVisibilityConverter.cs diff --git a/source/RevitLookup/Views/Converters/IconDescriptorConverter.cs b/source/RevitLookupObsolete/Views/Converters/IconDescriptorConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/IconDescriptorConverter.cs rename to source/RevitLookupObsolete/Views/Converters/IconDescriptorConverter.cs diff --git a/source/RevitLookup/Views/Converters/InverseCollectionEmptyVisibilityConverter.cs b/source/RevitLookupObsolete/Views/Converters/InverseCollectionEmptyVisibilityConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/InverseCollectionEmptyVisibilityConverter.cs rename to source/RevitLookupObsolete/Views/Converters/InverseCollectionEmptyVisibilityConverter.cs diff --git a/source/RevitLookup/Views/Converters/ObjectColorConverter.cs b/source/RevitLookupObsolete/Views/Converters/ObjectColorConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/ObjectColorConverter.cs rename to source/RevitLookupObsolete/Views/Converters/ObjectColorConverter.cs diff --git a/source/RevitLookup/Views/Converters/TimeToStringConverter.cs b/source/RevitLookupObsolete/Views/Converters/TimeToStringConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/TimeToStringConverter.cs rename to source/RevitLookupObsolete/Views/Converters/TimeToStringConverter.cs diff --git a/source/RevitLookup/Views/Converters/TreeViewSourceConverter.cs b/source/RevitLookupObsolete/Views/Converters/TreeViewSourceConverter.cs similarity index 100% rename from source/RevitLookup/Views/Converters/TreeViewSourceConverter.cs rename to source/RevitLookupObsolete/Views/Converters/TreeViewSourceConverter.cs diff --git a/source/RevitLookup/Views/Dialogs/EditParameterDialog.xaml b/source/RevitLookupObsolete/Views/Dialogs/EditParameterDialog.xaml similarity index 100% rename from source/RevitLookup/Views/Dialogs/EditParameterDialog.xaml rename to source/RevitLookupObsolete/Views/Dialogs/EditParameterDialog.xaml diff --git a/source/RevitLookup/Views/Dialogs/EditParameterDialog.xaml.cs b/source/RevitLookupObsolete/Views/Dialogs/EditParameterDialog.xaml.cs similarity index 100% rename from source/RevitLookup/Views/Dialogs/EditParameterDialog.xaml.cs rename to source/RevitLookupObsolete/Views/Dialogs/EditParameterDialog.xaml.cs diff --git a/source/RevitLookup/Views/Dialogs/EditSettingsEntryDialog.xaml b/source/RevitLookupObsolete/Views/Dialogs/EditSettingsEntryDialog.xaml similarity index 100% rename from source/RevitLookup/Views/Dialogs/EditSettingsEntryDialog.xaml rename to source/RevitLookupObsolete/Views/Dialogs/EditSettingsEntryDialog.xaml diff --git a/source/RevitLookup/Views/Dialogs/EditSettingsEntryDialog.xaml.cs b/source/RevitLookupObsolete/Views/Dialogs/EditSettingsEntryDialog.xaml.cs similarity index 100% rename from source/RevitLookup/Views/Dialogs/EditSettingsEntryDialog.xaml.cs rename to source/RevitLookupObsolete/Views/Dialogs/EditSettingsEntryDialog.xaml.cs diff --git a/source/RevitLookup/Views/Dialogs/FamilySizeTableEditDialog.xaml b/source/RevitLookupObsolete/Views/Dialogs/FamilySizeTableEditDialog.xaml similarity index 92% rename from source/RevitLookup/Views/Dialogs/FamilySizeTableEditDialog.xaml rename to source/RevitLookupObsolete/Views/Dialogs/FamilySizeTableEditDialog.xaml index 8fc2f307e..da939ecfc 100644 --- a/source/RevitLookup/Views/Dialogs/FamilySizeTableEditDialog.xaml +++ b/source/RevitLookupObsolete/Views/Dialogs/FamilySizeTableEditDialog.xaml @@ -18,11 +18,10 @@ - +