diff --git a/.editorconfig b/.editorconfig old mode 100644 new mode 100755 index fdd5106..8bd0f56 --- a/.editorconfig +++ b/.editorconfig @@ -10,7 +10,7 @@ indent_style = space # Code files [*.{cs,csx,vb,vbx}] -indent_size = 4 +indent_size = 2 insert_final_newline = true charset = utf-8-bom diff --git a/Grevit.Revit.2019/ExtEventHandler.cs b/Grevit.Revit.2019/ExtEventHandler.cs new file mode 100644 index 0000000..9e5b342 --- /dev/null +++ b/Grevit.Revit.2019/ExtEventHandler.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autodesk.Revit.UI; +using SpeckleClientUI; +using SpeckleCore; + +namespace Grevit.Revit +{ + /// + /// This one here works the magic + /// + public class SpeckleExternalEventHandler : IExternalEventHandler + { + public Receiver Receiver; + /// + /// Where the speckle build and bake gets triggered. + /// + /// + public void Execute( UIApplication app ) + { + // There's something wrong with the line below. + // TODO: Cleanup flow and referncing, etc. I obviously got confused in the process. + Receiver.Builder.Build( Receiver ); + } + + public string GetName( ) + { + return "Speckle Bake"; + } + } +} diff --git a/Grevit.Revit.2019/FodyWeavers.xml b/Grevit.Revit.2019/FodyWeavers.xml new file mode 100644 index 0000000..9ac681b --- /dev/null +++ b/Grevit.Revit.2019/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Grevit.Revit.2019/Grevit.Revit.2019.csproj b/Grevit.Revit.2019/Grevit.Revit.2019.csproj index bd93753..668ee88 100644 --- a/Grevit.Revit.2019/Grevit.Revit.2019.csproj +++ b/Grevit.Revit.2019/Grevit.Revit.2019.csproj @@ -1,5 +1,6 @@  + Debug @@ -12,6 +13,9 @@ v4.7.1 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + true @@ -31,16 +35,41 @@ 4 + + ..\packages\Costura.Fody.3.1.6\lib\net46\Costura.dll + + + ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll + + + ..\packages\MaterialDesignThemes.2.5.0.1205\lib\net45\MaterialDesignThemes.Wpf.dll + + - - C:\Program Files\Autodesk\Revit 2019\RevitAPI.dll + + ..\packages\Revit.RevitApi.x64.2019.0.0\lib\net45\RevitAPI.dll False - - C:\Program Files\Autodesk\Revit 2019\RevitAPIUI.dll + + ..\packages\Revit.RevitApiUI.x64.2019.0.0\lib\net45\RevitAPIUI.dll False + + ..\packages\sqlite-net-pcl.1.5.231\lib\netstandard1.1\SQLite-net.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_green.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_v2.dll + + + ..\packages\SQLitePCLRaw.core.1.1.11\lib\net45\SQLitePCLRaw.core.dll + + + ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.11\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + @@ -55,20 +84,20 @@ - ComponentExtension.cs + Grevit\ComponentExtension.cs - CreateExtension.cs + Grevit\CreateExtension.cs - ParameterExtension.cs + Grevit\ParameterExtension.cs - ParameterList.cs + Grevit\ParameterList.cs Form - ParameterList.Designer.cs + Grevit\ParameterList.Designer.cs Revit.cs @@ -76,18 +105,29 @@ Utilities.cs + + + + + + True True Resources.resx + + SpeckleClientWindow.xaml + + Always Designer + @@ -96,7 +136,7 @@ - ParameterList.resx + Grevit\ParameterList.resx ResXFileCodeGenerator @@ -108,11 +148,26 @@ {4e16464a-4495-4a27-b810-a54f9ce3d191} Grevit.Types + + {d65594c8-ea2e-46ca-a756-b1634edc3ae3} + SpecklePopup + + + {5ffc275e-4dc5-4351-a12d-10985bff4e04} + SpeckleClientUI + {cfe27d3d-8a1a-43f9-9387-8fd9e119e174} SpeckleCore + + + Designer + MSBuild:Compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\2xfucklogos@2x.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/SpeckleAccountManager/Properties/Settings.Designer.cs b/SpeckleAccountManager/Properties/Settings.Designer.cs new file mode 100644 index 0000000..6531477 --- /dev/null +++ b/SpeckleAccountManager/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpecklePopup.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/SpeckleAccountManager/Properties/Settings.settings b/SpeckleAccountManager/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/SpeckleAccountManager/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SpeckleAccountManager/README.md b/SpeckleAccountManager/README.md new file mode 100644 index 0000000..a6fe90c --- /dev/null +++ b/SpeckleAccountManager/README.md @@ -0,0 +1,2 @@ +# SpeckleAccountManager +Annoying popup that allows you to choose or create a Speckle Account. diff --git a/SpeckleAccountManager/Resources/2xfucklogos@2x.png b/SpeckleAccountManager/Resources/2xfucklogos@2x.png new file mode 100644 index 0000000..4fead22 Binary files /dev/null and b/SpeckleAccountManager/Resources/2xfucklogos@2x.png differ diff --git a/SpeckleAccountManager/SpecklePopup.csproj b/SpeckleAccountManager/SpecklePopup.csproj new file mode 100644 index 0000000..584e605 --- /dev/null +++ b/SpeckleAccountManager/SpecklePopup.csproj @@ -0,0 +1,171 @@ + + + + + Debug + AnyCPU + {D65594C8-EA2E-46CA-A756-B1634EDC3AE3} + Library + Properties + SpecklePopup + SpecklePopup + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + true + bin\DebugRevit\ + DEBUG;TRACE + full + AnyCPU + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + + + + + 4.0 + + + + + + + + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + AccountsUserControl.xaml + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + 11.0.2 + + + 1.5.231 + + + + + {cfe27d3d-8a1a-43f9-9387-8fd9e119e174} + SpeckleCore + + + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI.Test/App.config b/SpeckleClientUI.Test/App.config new file mode 100644 index 0000000..731f6de --- /dev/null +++ b/SpeckleClientUI.Test/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI.Test/App.xaml b/SpeckleClientUI.Test/App.xaml new file mode 100644 index 0000000..c24ce2f --- /dev/null +++ b/SpeckleClientUI.Test/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/SpeckleClientUI.Test/App.xaml.cs b/SpeckleClientUI.Test/App.xaml.cs new file mode 100644 index 0000000..cd682a0 --- /dev/null +++ b/SpeckleClientUI.Test/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SpeckleClientUI.Test +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/SpeckleClientUI.Test/MainWindow.xaml b/SpeckleClientUI.Test/MainWindow.xaml new file mode 100644 index 0000000..d487fdc --- /dev/null +++ b/SpeckleClientUI.Test/MainWindow.xaml @@ -0,0 +1,15 @@ + + + + + diff --git a/SpeckleClientUI.Test/MainWindow.xaml.cs b/SpeckleClientUI.Test/MainWindow.xaml.cs new file mode 100755 index 0000000..8b0b3fb --- /dev/null +++ b/SpeckleClientUI.Test/MainWindow.xaml.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using SpeckleClientUI; +using SpeckleCore; + +namespace SpeckleClientUI.Test +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + receiver.OnUpdateGlobal += Receiver_OnUpdateGlobal; + } + + private void Receiver_OnUpdateGlobal(Receiver receiver) + { + Console.WriteLine(receiver.StreamId); + } + + } +} diff --git a/SpeckleClientUI.Test/Properties/AssemblyInfo.cs b/SpeckleClientUI.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b3e1e09 --- /dev/null +++ b/SpeckleClientUI.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SpeckleClientUI.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SpeckleClientUI.Test")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SpeckleClientUI.Test/Properties/Resources.Designer.cs b/SpeckleClientUI.Test/Properties/Resources.Designer.cs new file mode 100644 index 0000000..0aa6b5b --- /dev/null +++ b/SpeckleClientUI.Test/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpeckleClientUI.Test.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SpeckleClientUI.Test.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/SpeckleClientUI.Test/Properties/Resources.resx b/SpeckleClientUI.Test/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/SpeckleClientUI.Test/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SpeckleClientUI.Test/Properties/Settings.Designer.cs b/SpeckleClientUI.Test/Properties/Settings.Designer.cs new file mode 100644 index 0000000..645476b --- /dev/null +++ b/SpeckleClientUI.Test/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpeckleClientUI.Test.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/SpeckleClientUI.Test/Properties/Settings.settings b/SpeckleClientUI.Test/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/SpeckleClientUI.Test/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI.Test/SpeckleClientUI.Test.csproj b/SpeckleClientUI.Test/SpeckleClientUI.Test.csproj new file mode 100644 index 0000000..42e241e --- /dev/null +++ b/SpeckleClientUI.Test/SpeckleClientUI.Test.csproj @@ -0,0 +1,143 @@ + + + + + Debug + AnyCPU + {B5511A1D-73EF-4B1B-AAFE-276B109188E8} + WinExe + SpeckleClientUI.Test + SpeckleClientUI.Test + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll + + + ..\packages\MaterialDesignThemes.2.5.1-ci1219\lib\net45\MaterialDesignThemes.Wpf.dll + + + ..\packages\sqlite-net-pcl.1.5.231\lib\netstandard1.1\SQLite-net.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_green.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_v2.dll + + + ..\packages\SQLitePCLRaw.core.1.1.11\lib\net45\SQLitePCLRaw.core.dll + + + ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.11\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {5ffc275e-4dc5-4351-a12d-10985bff4e04} + SpeckleClientUI + + + {cfe27d3d-8a1a-43f9-9387-8fd9e119e174} + SpeckleCore + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI.Test/packages.config b/SpeckleClientUI.Test/packages.config new file mode 100644 index 0000000..068ea11 --- /dev/null +++ b/SpeckleClientUI.Test/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI/Data/Commands.cs b/SpeckleClientUI/Data/Commands.cs new file mode 100644 index 0000000..7d47576 --- /dev/null +++ b/SpeckleClientUI/Data/Commands.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Input; + +namespace SpeckleClientUI.Data +{ + public static class Commands + { + public static readonly RoutedCommand ReceiveStream = new RoutedCommand("ReceiveStream", typeof(Button)); + + } +} diff --git a/SpeckleClientUI/Data/IContext.cs b/SpeckleClientUI/Data/IContext.cs new file mode 100644 index 0000000..98d7f6b --- /dev/null +++ b/SpeckleClientUI/Data/IContext.cs @@ -0,0 +1,11 @@ +using System; + +namespace SpeckleClientUI.Data +{ + public interface IContext + { + bool IsSynchronized { get; } + void Invoke(Action action); + void BeginInvoke(Action action); + } +} diff --git a/SpeckleClientUI/Interfaces.cs b/SpeckleClientUI/Interfaces.cs new file mode 100644 index 0000000..2c76062 --- /dev/null +++ b/SpeckleClientUI/Interfaces.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SpeckleCore; + +namespace SpeckleClientUI +{ + /// + /// TODO: Extract to separate ui project + /// Defines a build method that needs to be implemented by any potential speckle baker. + /// + public interface ISpeckleHostBuilder + { + void Build( Receiver receiver ); + } + + /// + /// TODO: Extract to separate ui project. + /// + public interface ISpeckleHostBuilderGenerator + { + /// + /// Factory for getting the builder set up with app accesible document, etc. + /// + /// + ISpeckleHostBuilder GetHostBuilder( ); + } +} diff --git a/SpeckleClientUI/Properties/AssemblyInfo.cs b/SpeckleClientUI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..dd0d301 --- /dev/null +++ b/SpeckleClientUI/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SpeckleClientUI")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SpeckleClientUI")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly:ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SpeckleClientUI/Properties/Resources.Designer.cs b/SpeckleClientUI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3fa8db0 --- /dev/null +++ b/SpeckleClientUI/Properties/Resources.Designer.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpeckleClientUI.Properties { + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if ((resourceMan == null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SpeckleClientUI.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/SpeckleClientUI/Properties/Resources.resx b/SpeckleClientUI/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/SpeckleClientUI/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SpeckleClientUI/Properties/Settings.Designer.cs b/SpeckleClientUI/Properties/Settings.Designer.cs new file mode 100644 index 0000000..91d9f3c --- /dev/null +++ b/SpeckleClientUI/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SpeckleClientUI.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/SpeckleClientUI/Properties/Settings.settings b/SpeckleClientUI/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/SpeckleClientUI/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI/Receiver.cs b/SpeckleClientUI/Receiver.cs new file mode 100644 index 0000000..532c9c1 --- /dev/null +++ b/SpeckleClientUI/Receiver.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Input; +using System.Windows.Threading; +using SpeckleClientUI.Data; +using SpeckleCore; + +namespace SpeckleClientUI +{ + public class Receiver : INotifyPropertyChanged, IContext + { + private string _authToken; + private string _restApi; + private string _email; + private string _server; + private string _streamId; + private string _streamName; + private string _message; + private bool _transmitting; + private bool _expired = true; + private SpeckleApiClient _client; + + internal string AuthToken { get => _authToken; set { _authToken = value; NotifyPropertyChanged( "AuthToken" ); } } + + public string RestApi { get => _restApi; set { _restApi = value; NotifyPropertyChanged( "RestApi" ); } } + public string Email { get => _email; set { _email = value; NotifyPropertyChanged( "Email" ); } } + public string Server { get => _server; set { _server = value; NotifyPropertyChanged( "Server" ); } } + public string StreamId { get => _streamId; set { _streamId = value; NotifyPropertyChanged( "StreamId" ); } } + public string StreamName { get => _streamName; set { _streamName = value; NotifyPropertyChanged( "StreamName" ); } } + public string Message { get => _message; set { _message = value; NotifyPropertyChanged( "Message" ); } } + public bool Transmitting + { + get => _transmitting; + set + { + _transmitting = value; + NotifyPropertyChanged( "Transmitting" ); + + _dispatcher.Invoke( new Action( ( ) => + CommandManager.InvalidateRequerySuggested() + ) ); + + } + } + public bool Expired { get => _expired; set { _expired = value; NotifyPropertyChanged( "Expired" ); } } + + /// + /// Keeps track of the previous version of the stream. + /// + public SpeckleStream Stream; + + /// + /// Keeps track of the previous version of the stream. + /// + public SpeckleStream PreviousStream; + + /// + /// Hidden hidden secret secret + /// + public SpeckleStream _PreviousStream; + + /// + /// Does the heavy lifting + /// + public ISpeckleHostBuilder Builder; + + public double Scale = 1; + + private readonly Dispatcher _dispatcher; + + public bool IsSynchronized + { + get + { + return this._dispatcher.Thread == Thread.CurrentThread; + } + } + + public Receiver( Dispatcher dispatcher, string streamid, string server, string restapi, string authtoken, string email ) + { + this._dispatcher = dispatcher; + + Transmitting = true; + + StreamId = streamid; + Email = email; + Server = server; + RestApi = restapi; + AuthToken = authtoken; + + _client = new SpeckleApiClient( RestApi, true ); + + _client.OnReady += ( sender, e ) => + { + UpdateMeta(); + Stream = _client.Stream; + PreviousStream = new SpeckleStream() { Objects = new List() }; + }; + + _client.OnWsMessage += OnWsMessage; + + _client.OnError += ( sender, e ) => + { + Console.Write( e ); + }; + + // TODO Set document name, etc. from Builder object + _client.IntializeReceiver( StreamId, "", "Dynamo", "", AuthToken ); + } + + public virtual void UpdateGlobal( ) + { + Transmitting = true; + Stream = _client.StreamGetAsync( _client.StreamId, null ).Result.Resource; + StreamName = Stream.Name; + + Message = "Getting objects"; + + LocalContext.GetObjects( Stream.Objects, _client.BaseUrl ); + + // filter out the objects that were not in the cache and still need to be retrieved + var payload = Stream.Objects.Where( o => o.Type == SpeckleObjectType.Placeholder ).Select( obj => obj._id ).ToArray(); + + // how many objects to request from the api at a time + int maxObjRequestCount = 20; + + // list to hold them into + var newObjects = new List(); + + // jump in `maxObjRequestCount` increments through the payload array + for ( int i = 0; i < payload.Length; i += maxObjRequestCount ) + { + // create a subset + var subPayload = payload.Skip( i ).Take( maxObjRequestCount ).ToArray(); + + // get it sync as this is always execed out of the main thread + var res = _client.ObjectGetBulkAsync( subPayload, "omit=displayValue" ).Result; + + // put them in our bucket + newObjects.AddRange( res.Resources ); + + // TODO: Bind this message to somewhere! + Message = String.Format( "Got {0} out of {1} objects.", i, payload.Length ); + System.Diagnostics.Debug.WriteLine( String.Format( "Got {0} out of {1} objects.", i, payload.Length ) ); + } + + // populate the retrieved objects in the original stream's object list + foreach ( var obj in newObjects ) + { + var locationInStream = Stream.Objects.FindIndex( o => o._id == obj._id ); + try { Stream.Objects[ locationInStream ] = obj; } catch { } + + // add objects to cache + LocalContext.AddObject( obj, _client.BaseUrl ); + } + + var units = ( ( string ) Stream.BaseProperties.units ).ToLower(); + + // TODO: Check + switch ( units ) + { + case "kilometers": + Scale = 3.2808399 * 1000; + break; + case "meters": + Scale = 3.2808399; + break; + case "centimeters": + Scale = 0.032808399; + break; + case "millimiters": + Scale = 0.0032808399; + break; + case "miles": + Scale = 5280; + break; + case "feet": + Scale = 1; + break; + case "inches": + Scale = 0.0833333; + break; + }; + + Transmitting = false; + Expired = false; + } + + public virtual void UpdateMeta( ) + { + var result = _client.StreamGetAsync( _client.StreamId, "fields=name" ).Result; + + Stream = result.Resource; + + StreamName = result.Resource.Name; + Transmitting = false; + } + + public virtual void OnWsMessage( object source, SpeckleEventArgs e ) + { + switch ( ( string ) e.EventObject.args.eventType ) + { + case "update-global": + Message = "Update available since " + DateTime.Now; + Expired = true; + break; + case "update-meta": + UpdateMeta(); + break; + case "update-name": + UpdateMeta(); + break; + default: + //CustomMessageHandler((string)e.EventObject.args.eventType, e); + break; + } + } + + public void Invoke( Action action ) + { + Debug.Assert( action != null ); + + this._dispatcher.Invoke( action ); + } + + public void BeginInvoke( Action action ) + { + Debug.Assert( action != null ); + + this._dispatcher.BeginInvoke( action ); + } + + public event PropertyChangedEventHandler PropertyChanged; + private void NotifyPropertyChanged( string info ) + { + if ( PropertyChanged != null ) + { + PropertyChanged( this, new PropertyChangedEventArgs( info ) ); + } + } + + /// + /// Makes sure diffing happens correctly by commiting the last stage to memory only + /// on a succesfull operation. + /// + public void CommitStage( ) + { + PreviousStream = SpeckleStream.FromJson( Stream.ToJson() ); + } + + } + + //only used for the DesignData xaml + public class Receivers : List + { + public Receivers( ) { } + } +} diff --git a/SpeckleClientUI/ReceiversUi.xaml b/SpeckleClientUI/ReceiversUi.xaml new file mode 100755 index 0000000..fa55b6a --- /dev/null +++ b/SpeckleClientUI/ReceiversUi.xaml @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpeckleClientUI/ReceiversUi.xaml.cs b/SpeckleClientUI/ReceiversUi.xaml.cs new file mode 100644 index 0000000..afc2c31 --- /dev/null +++ b/SpeckleClientUI/ReceiversUi.xaml.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Threading; +using SpeckleCore; + +namespace SpeckleClientUI +{ + /// + /// Interaction logic for Receiver.xaml + /// + public partial class ReceiversUi : UserControl + { + private ObservableCollection _receivers = new ObservableCollection(); + private ObservableCollection _accounts = new ObservableCollection(); + + public delegate void ReceivedData( Receiver receiver ); + public event ReceivedData OnUpdateGlobal; + + public delegate void ReceiverAdded( Receiver receiver ); + public event ReceiverAdded OnReceiverAdded; + + public ISpeckleHostBuilderGenerator BuildGenerator; + + public ReceiversUi( ) + { + InitializeComponent(); + RefreshAccounts(); + } + + public void RefreshAccounts( ) + { + LocalContext.Init(); + _accounts = new ObservableCollection( LocalContext.GetAllAccounts() ); + AccountsComboBox.ItemsSource = _accounts; + if ( _accounts.Any( x => x.IsDefault ) ) + { + AccountsComboBox.SelectedIndex = _accounts.IndexOf( _accounts.First( x => x.IsDefault ) ); + } + + ReceiverItemsControl.ItemsSource = _receivers; + } + + private void NewReceiverClick( object sender, RoutedEventArgs e ) + { + if ( StreamsComboBox.SelectedIndex == -1 || AccountsComboBox.SelectedIndex == -1 ) + return; + + var stream = StreamsComboBox.SelectedItem as SpeckleStream; + var account = _accounts[ AccountsComboBox.SelectedIndex ]; + + // check if the stream is already there + if (_receivers.Where(rec => rec.StreamId == stream.StreamId && rec.RestApi == account.RestApi).Any()) + { + MessageBox.Show( "This stream has already been added!", @"¯\_(ツ)_/¯" ); + return; + } + + _receivers.Add( new Receiver( this.Dispatcher, stream.StreamId, account.ServerName, account.RestApi, account.Token, account.Email ) { Builder = BuildGenerator.GetHostBuilder() } ); + } + + #region commands + + private void OnClickReceiveStream( object sender, ExecutedRoutedEventArgs e ) + { + var r = e.Parameter as Receiver; + + r.UpdateGlobal(); + OnUpdateGlobal( r ); + } + + + + private void CommandBinding_CanExecute( object sender, CanExecuteRoutedEventArgs e ) + { + + if ( _receivers.Any( x => x.Transmitting ) ) + { + e.CanExecute = false; + } + else + { + e.CanExecute = true; + } + } + + #endregion + + private void PasteClick( object sender, RoutedEventArgs e ) + { + //var c = Clipboard.GetText(); + //if (c.Length>10) + // c = c.Substring(0, 10); + //StreamId.Text = c; + } + + private void AccountsClick( object sender, RoutedEventArgs e ) + { + var myForm = new SpecklePopup.MainWindow( false ); + myForm.ShowDialog(); + RefreshAccounts(); + } + + private async void AccountsComboBoxSelectionChanged( object sender, SelectionChangedEventArgs e ) + { + if ( AccountsComboBox.SelectedIndex == -1 ) + { + return; + } + + var client = new SpeckleApiClient(); + var account = _accounts[ AccountsComboBox.SelectedIndex ]; + + client.BaseUrl = account.RestApi; + client.AuthToken = account.Token; + + try + { + var getStreams = await client.StreamsGetAllAsync(); + StreamsComboBox.ItemsSource = getStreams.Resources; + } + catch + { + // TODO: Handle bad/offline account + } + + client.Dispose(); + } + } + + +} diff --git a/SpeckleClientUI/SampleReceiverData.xaml b/SpeckleClientUI/SampleReceiverData.xaml new file mode 100755 index 0000000..184c145 --- /dev/null +++ b/SpeckleClientUI/SampleReceiverData.xaml @@ -0,0 +1,29 @@ + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI/SpeckleClientUI.csproj b/SpeckleClientUI/SpeckleClientUI.csproj new file mode 100644 index 0000000..febbb29 --- /dev/null +++ b/SpeckleClientUI/SpeckleClientUI.csproj @@ -0,0 +1,125 @@ + + + + + Debug + AnyCPU + {5FFC275E-4DC5-4351-A12D-10985BFF4E04} + library + SpeckleClientUI + SpeckleClientUI + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MaterialDesignColors.1.1.3\lib\net45\MaterialDesignColors.dll + + + ..\packages\MaterialDesignThemes.2.5.1-ci1219\lib\net45\MaterialDesignThemes.Wpf.dll + + + + + + + + + + + 4.0 + + + + + + + + + + + ReceiversUi.xaml + + + + AutoCompleteComboBox.xaml + + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + {d65594c8-ea2e-46ca-a756-b1634edc3ae3} + SpecklePopup + + + {cfe27d3d-8a1a-43f9-9387-8fd9e119e174} + SpeckleCore + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI/Themes/Generic.xaml b/SpeckleClientUI/Themes/Generic.xaml new file mode 100644 index 0000000..13b3012 --- /dev/null +++ b/SpeckleClientUI/Themes/Generic.xaml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml b/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml new file mode 100644 index 0000000..8044050 --- /dev/null +++ b/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml @@ -0,0 +1,12 @@ + diff --git a/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml.cs b/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml.cs new file mode 100644 index 0000000..08b9b32 --- /dev/null +++ b/SpeckleClientUI/UserControls/AutoCompleteComboBox.xaml.cs @@ -0,0 +1,322 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; + +namespace SpeckleClientUI.UserControls +{ + /// + /// https://github.com/vain0x/DotNetKit.Wpf.AutoCompleteComboBox + /// + public partial class AutoCompleteComboBox : ComboBox + { + readonly SerialDisposable disposable = new SerialDisposable(); + + TextBox editableTextBoxCache; + public TextBox EditableTextBox + { + get + { + if (editableTextBoxCache == null) + { + const string name = "PART_EditableTextBox"; + editableTextBoxCache = (TextBox)VisualTreeModule.FindChild(this, name); + } + return editableTextBoxCache; + } + } + + /// + /// Gets text to match with the query from an item. + /// Never null. + /// + /// + /// + string TextFromItem(object item) + { + if (item == null) return ""; + + var d = new DependencyVariable(); + d.SetBinding(item, TextSearch.GetTextPath(this)); + return d.Value ?? ""; + } + + #region Setting + static readonly DependencyProperty settingProperty = + DependencyProperty.Register( + "Setting", + typeof(AutoCompleteComboBoxSetting), + typeof(AutoCompleteComboBox) + ); + + public static DependencyProperty SettingProperty + { + get { return settingProperty; } + } + + public AutoCompleteComboBoxSetting Setting + { + get { return (AutoCompleteComboBoxSetting)GetValue(SettingProperty); } + set { SetValue(SettingProperty, value); } + } + + AutoCompleteComboBoxSetting SettingOrDefault + { + get { return Setting ?? AutoCompleteComboBoxSetting.Default; } + } + #endregion + + #region OnTextChanged + long revisionId; + string previousText; + + struct TextBoxStatePreserver + : IDisposable + { + readonly TextBox textBox; + readonly int selectionStart; + readonly int selectionLength; + readonly string text; + + public void Dispose() + { + textBox.Text = text; + textBox.Select(selectionStart, selectionLength); + } + + public TextBoxStatePreserver(TextBox textBox) + { + this.textBox = textBox; + selectionStart = textBox.SelectionStart; + selectionLength = textBox.SelectionLength; + text = textBox.Text; + } + } + + static int CountWithMax(IEnumerable xs, Func predicate, int maxCount) + { + var count = 0; + foreach (var x in xs) + { + if (predicate(x)) + { + count++; + if (count > maxCount) return count; + } + } + return count; + } + + void Unselect() + { + var textBox = EditableTextBox; + textBox.Select(textBox.SelectionStart + textBox.SelectionLength, 0); + } + + void UpdateFilter(Func filter) + { + using (new TextBoxStatePreserver(EditableTextBox)) + using (Items.DeferRefresh()) + { + // Can empty the text box. I don't why. + Items.Filter = item => filter(item); + } + } + + void OpenDropDown(Func filter) + { + UpdateFilter(filter); + IsDropDownOpen = true; + Unselect(); + } + + void OpenDropDown() + { + var setting = SettingOrDefault; + var filter = setting.GetFilter(Text, TextFromItem); + OpenDropDown(filter); + } + + void UpdateSuggestionList() + { + var text = Text; + + if (text == previousText) return; + previousText = text; + + if (string.IsNullOrEmpty(text)) + { + IsDropDownOpen = false; + SelectedItem = null; + + using (Items.DeferRefresh()) + { + Items.Filter = null; + } + } + else if (SelectedItem != null && TextFromItem(SelectedItem) == text) + { + // It seems the user selected an item. + // Do nothing. + } + else + { + using (new TextBoxStatePreserver(EditableTextBox)) + { + SelectedItem = null; + } + + var setting = SettingOrDefault; + var filter = setting.GetFilter(text, TextFromItem); + var maxCount = setting.MaxSuggestionCount; + var count = CountWithMax(ItemsSource.Cast(), filter, maxCount); + + if (count > maxCount) return; + + OpenDropDown(filter); + } + } + + void OnTextChanged(object sender, TextChangedEventArgs e) + { + var id = unchecked(++revisionId); + var setting = SettingOrDefault; + + if (setting.Delay <= TimeSpan.Zero) + { + UpdateSuggestionList(); + return; + } + + disposable.Content = + new Timer( + state => + { + Dispatcher.InvokeAsync(() => + { + if (revisionId != id) return; + UpdateSuggestionList(); + }); + }, + null, + setting.Delay, + Timeout.InfiniteTimeSpan + ); + } + #endregion + + void ComboBox_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && e.Key == Key.Space) + { + OpenDropDown(); + e.Handled = true; + } + } + + public AutoCompleteComboBox() + { + InitializeComponent(); + + AddHandler( + TextBoxBase.TextChangedEvent, + new TextChangedEventHandler(OnTextChanged) + ); + } + } + + sealed class DependencyVariable + : DependencyObject + { + static readonly DependencyProperty valueProperty = + DependencyProperty.Register( + "Value", + typeof(T), + typeof(DependencyVariable) + ); + + public static DependencyProperty ValueProperty + { + get { return valueProperty; } + } + + public T Value + { + get { return (T)GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + + public void SetBinding(Binding binding) + { + BindingOperations.SetBinding(this, ValueProperty, binding); + } + + public void SetBinding(object dataContext, string propertyPath) + { + SetBinding(new Binding(propertyPath) { Source = dataContext }); + } + } + + static class VisualTreeModule + { + public static FrameworkElement FindChild(DependencyObject obj, string childName) + { + if (obj == null) return null; + + var queue = new Queue(); + queue.Enqueue(obj); + + while (queue.Count > 0) + { + obj = queue.Dequeue(); + + var childCount = VisualTreeHelper.GetChildrenCount(obj); + for (var i = 0; i < childCount; i++) + { + var child = VisualTreeHelper.GetChild(obj, i); + + var fe = child as FrameworkElement; + if (fe != null && fe.Name == childName) + { + return fe; + } + + queue.Enqueue(child); + } + } + + return null; + } + } + + sealed class SerialDisposable + : IDisposable + { + IDisposable content; + + public IDisposable Content + { + get { return content; } + set + { + if (content != null) + { + content.Dispose(); + } + + content = value; + } + } + + public void Dispose() + { + Content = null; + } + } +} diff --git a/SpeckleClientUI/UserControls/AutoCompleteComboBoxSetting.cs b/SpeckleClientUI/UserControls/AutoCompleteComboBoxSetting.cs new file mode 100644 index 0000000..087a561 --- /dev/null +++ b/SpeckleClientUI/UserControls/AutoCompleteComboBoxSetting.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SpeckleClientUI.UserControls +{ + /// + /// https://github.com/vain0x/DotNetKit.Wpf.AutoCompleteComboBox + /// + public class AutoCompleteComboBoxSetting + { + /// + /// Gets a filter function which determines whether items should be suggested or not + /// for the specified query. + /// Default: Gets the filter which maps an item to true + /// if its text contains the query (case insensitive). + /// + /// + /// The string input by user. + /// + /// + /// The function to get a string which identifies the specified item. + /// + /// + public virtual Func + GetFilter(string query, Func stringFromItem) + { + return + item => + stringFromItem(item) + .IndexOf(query, StringComparison.InvariantCultureIgnoreCase) >= 0; + } + + /// + /// Gets an integer. + /// The combobox opens the drop down + /// if the number of suggested items is less than the value. + /// Note that the value is larger, it's heavier to open the drop down. + /// Default: 100. + /// + public virtual int MaxSuggestionCount + { + get { return 1000; } + } + + /// + /// Gets the duration to delay updating the suggestion list. + /// Returns Zero if no delay. + /// Default: 300ms. + /// + public virtual TimeSpan Delay + { + get { return TimeSpan.FromMilliseconds(200.0); } + } + + static AutoCompleteComboBoxSetting @default = + new AutoCompleteComboBoxSetting(); + + /// + /// Gets the default setting. + /// + public static AutoCompleteComboBoxSetting Default + { + get { return @default; } + set + { + if (value == null) throw new ArgumentNullException("value"); + @default = value; + } + } + } +} diff --git a/SpeckleClientUI/ValueConverters/BoolVisibConverter.cs b/SpeckleClientUI/ValueConverters/BoolVisibConverter.cs new file mode 100644 index 0000000..918a35d --- /dev/null +++ b/SpeckleClientUI/ValueConverters/BoolVisibConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace SpeckleClientUI.ValueConverters +{ + /// + /// return visible if true. + /// can set second parameter to be "opposite" to reverse the functionality + /// + [ValueConversion(typeof(String), typeof(Visibility))] + public class BoolVisibConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + value = false; + bool c = (bool)value; + + if (parameter != null && parameter.ToString() == "opposite") + c = !c; + + return (c) ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + + throw new NotImplementedException(); + } + } +} diff --git a/SpeckleClientUI/ValueConverters/InvertBoolConverter.cs b/SpeckleClientUI/ValueConverters/InvertBoolConverter.cs new file mode 100644 index 0000000..80b957f --- /dev/null +++ b/SpeckleClientUI/ValueConverters/InvertBoolConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace SpeckleClientUI.ValueConverters +{ + [ValueConversion(typeof(bool), typeof(bool))] + public class InvertBoolConverter : IValueConverter + { + public InvertBoolConverter() + { + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value != null && value is bool) + { + return !((bool)value); + } + + return true; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return Convert(value, targetType, parameter, culture); + } + } +} diff --git a/SpeckleClientUI/packages.config b/SpeckleClientUI/packages.config new file mode 100644 index 0000000..04eca74 --- /dev/null +++ b/SpeckleClientUI/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/SpeckleCore b/SpeckleCore index 7885986..0ba6b37 160000 --- a/SpeckleCore +++ b/SpeckleCore @@ -1 +1 @@ -Subproject commit 7885986ab793fbb24b0ed0485c48e1bed29007da +Subproject commit 0ba6b37f13bd2895f230231ae34c5f803b99da6a