From 81af2d3c8cf632d7634af6df2a451d2d0e923c81 Mon Sep 17 00:00:00 2001 From: Vitali Semianiaka Date: Wed, 14 Apr 2021 16:26:56 +0300 Subject: [PATCH] .net copy --- BrightSharp.NET/AssemblyInfo.cs | 26 + .../FilterDefaultViewTextBoxBehavior.cs | 117 + BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs | 80 + .../Behaviors/SelectAllTextOnFocusBehavior.cs | 33 + .../Behaviors/WindowMinMaxSizeBehavior.cs | 23 + .../FilterDefaultViewTextBoxBehavior.cs | 117 + .../Behaviors/MinMaxSize_Logic.cs | 80 + .../Behaviors/SelectAllTextOnFocusBehavior.cs | 33 + .../Behaviors/WindowMinMaxSizeBehavior.cs | 23 + .../BrightSharp.NET/BrightSharp.NET.csproj | 170 + .../BrightSharp.NET/Commands/AsyncCommand.cs | 74 + .../BrightSharp.NET/Commands/RelayCommand.cs | 71 + .../Converters/IntToValueConverter.cs | 60 + .../InverseBooleanToVisibilityConverter.cs | 23 + .../Converters/ThicknessConverter.cs | 40 + .../Diagrams/Adorners/ResizeRotateAdorner.cs | 48 + .../Diagrams/Adorners/ResizeRotateChrome.cs | 15 + .../Diagrams/Adorners/SizeAdorner.cs | 46 + .../Diagrams/Adorners/SizeChrome.cs | 34 + .../Diagrams/DesignerItemDecorator.cs | 103 + .../Diagrams/SelectionBehavior.cs | 96 + .../Diagrams/Thumbs/MoveThumb.cs | 75 + .../Diagrams/Thumbs/ResizeThumb.cs | 160 + .../Diagrams/Thumbs/RotateThumb.cs | 88 + .../Diagrams/VisualExtensions.cs | 132 + .../BrightSharp.NET/Diagrams/ZoomControl.cs | 228 + .../Extensions/MarkupExtensionProperties.cs | 168 + .../Extensions/WpfExtensions.cs | 142 + .../BrightSharp.NET/Interop/Constants.cs | 11 + .../BrightSharp.NET/Interop/NativeMethods.cs | 20 + .../BrightSharp.NET/Interop/Structures.cs | 130 + .../Properties/AssemblyInfo.cs | 26 + .../Properties/Resources.Designer.cs | 63 + .../BrightSharp.NET/Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../Themes/Controls/ZoomControl.xaml | 38 + .../Themes/Diagrams/DesignerItem.xaml | 43 + .../Themes/Diagrams/ResizeRotateChrome.xaml | 114 + .../Themes/Diagrams/SizeChrome.xaml | 49 + .../BrightSharp.NET/Themes/Generic.xaml | 5 + .../BrightSharp.NET/Themes/Style.Blue.xaml | 326 + .../BrightSharp.NET/Themes/Style.Classic.xaml | 283 + .../Themes/Style.DarkBlue.xaml | 307 + .../BrightSharp.NET/Themes/Style.DevLab.xaml | 274 + .../BrightSharp.NET/Themes/Style.Silver.xaml | 324 + .../BrightSharp.NET/Themes/Theme.Static.cs | 41 + .../BrightSharp.NET/Themes/Theme.Static.xaml | 5729 ++++++++++++++++ .../BrightSharp.NET/Themes/Theme.cs | 40 + .../BrightSharp.NET/Themes/Theme.xaml | 5760 +++++++++++++++++ .../BrightSharp.NET/Themes/ThemeManager.cs | 76 + .../BrightSharp.NET/Themes/icons/app.png | Bin 0 -> 367 bytes .../BrightSharp.NET/Themes/icons/copy.png | Bin 0 -> 503 bytes .../BrightSharp.NET/Themes/icons/cut.png | Bin 0 -> 510 bytes .../BrightSharp.NET/Themes/icons/paste.png | Bin 0 -> 715 bytes .../BrightSharp.NET/Themes/icons/undo.png | Bin 0 -> 1307 bytes .../BrightSharp.NET/packages.config | 4 + BrightSharp.NET/BrightSharp.csproj | 74 + BrightSharp.NET/Commands/AsyncCommand.cs | 74 + BrightSharp.NET/Commands/RelayCommand.cs | 71 + .../Converters/IntToValueConverter.cs | 60 + .../InverseBooleanToVisibilityConverter.cs | 23 + .../Converters/ThicknessConverter.cs | 40 + .../Diagrams/Adorners/ResizeRotateAdorner.cs | 48 + .../Diagrams/Adorners/ResizeRotateChrome.cs | 15 + .../Diagrams/Adorners/SizeAdorner.cs | 46 + .../Diagrams/Adorners/SizeChrome.cs | 34 + .../Diagrams/DesignerItemDecorator.cs | 103 + BrightSharp.NET/Diagrams/SelectionBehavior.cs | 96 + BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs | 75 + .../Diagrams/Thumbs/ResizeThumb.cs | 160 + .../Diagrams/Thumbs/RotateThumb.cs | 88 + BrightSharp.NET/Diagrams/VisualExtensions.cs | 132 + BrightSharp.NET/Diagrams/ZoomControl.cs | 228 + .../Extensions/MarkupExtensionProperties.cs | 168 + BrightSharp.NET/Extensions/WpfExtensions.cs | 142 + BrightSharp.NET/Interop/Constants.cs | 11 + BrightSharp.NET/Interop/NativeMethods.cs | 20 + BrightSharp.NET/Interop/Structures.cs | 130 + BrightSharp.NET/Properties/AssemblyInfo.cs | 63 + .../Properties/Resources.Designer.cs | 63 + BrightSharp.NET/Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 26 + BrightSharp.NET/Properties/Settings.settings | 7 + .../Themes/Controls/ZoomControl.xaml | 38 + .../Themes/Diagrams/DesignerItem.xaml | 43 + .../Themes/Diagrams/ResizeRotateChrome.xaml | 114 + .../Themes/Diagrams/SizeChrome.xaml | 49 + BrightSharp.NET/Themes/Generic.xaml | 5 + BrightSharp.NET/Themes/Style.Blue.xaml | 326 + BrightSharp.NET/Themes/Style.Classic.xaml | 283 + BrightSharp.NET/Themes/Style.DarkBlue.xaml | 307 + BrightSharp.NET/Themes/Style.DevLab.xaml | 274 + BrightSharp.NET/Themes/Style.Silver.xaml | 324 + BrightSharp.NET/Themes/Theme.Static.cs | 41 + BrightSharp.NET/Themes/Theme.Static.xaml | 5729 ++++++++++++++++ BrightSharp.NET/Themes/Theme.cs | 40 + BrightSharp.NET/Themes/Theme.xaml | 5760 +++++++++++++++++ BrightSharp.NET/Themes/ThemeManager.cs | 76 + BrightSharp.NET/Themes/icons/app.png | Bin 0 -> 367 bytes BrightSharp.NET/Themes/icons/copy.png | Bin 0 -> 503 bytes BrightSharp.NET/Themes/icons/cut.png | Bin 0 -> 510 bytes BrightSharp.NET/Themes/icons/paste.png | Bin 0 -> 715 bytes BrightSharp.NET/Themes/icons/undo.png | Bin 0 -> 1307 bytes BrightSharp.NET/packages.config | 4 + 105 files changed, 31645 insertions(+) create mode 100644 BrightSharp.NET/AssemblyInfo.cs create mode 100644 BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs create mode 100644 BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs create mode 100644 BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs create mode 100644 BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/BrightSharp.NET.csproj create mode 100644 BrightSharp.NET/BrightSharp.NET/Commands/AsyncCommand.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Commands/RelayCommand.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Converters/IntToValueConverter.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Converters/ThicknessConverter.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/SelectionBehavior.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/VisualExtensions.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Diagrams/ZoomControl.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Extensions/WpfExtensions.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Interop/Constants.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Interop/NativeMethods.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Interop/Structures.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Properties/AssemblyInfo.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Properties/Resources.Designer.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Properties/Resources.resx create mode 100644 BrightSharp.NET/BrightSharp.NET/Properties/Settings.Designer.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Properties/Settings.settings create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Controls/ZoomControl.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Generic.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Style.Blue.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Style.Classic.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Style.DarkBlue.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Style.DevLab.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Style.Silver.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Theme.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/Theme.xaml create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/ThemeManager.cs create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/icons/app.png create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/icons/copy.png create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/icons/cut.png create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/icons/paste.png create mode 100644 BrightSharp.NET/BrightSharp.NET/Themes/icons/undo.png create mode 100644 BrightSharp.NET/BrightSharp.NET/packages.config create mode 100644 BrightSharp.NET/BrightSharp.csproj create mode 100644 BrightSharp.NET/Commands/AsyncCommand.cs create mode 100644 BrightSharp.NET/Commands/RelayCommand.cs create mode 100644 BrightSharp.NET/Converters/IntToValueConverter.cs create mode 100644 BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs create mode 100644 BrightSharp.NET/Converters/ThicknessConverter.cs create mode 100644 BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs create mode 100644 BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs create mode 100644 BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs create mode 100644 BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs create mode 100644 BrightSharp.NET/Diagrams/DesignerItemDecorator.cs create mode 100644 BrightSharp.NET/Diagrams/SelectionBehavior.cs create mode 100644 BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs create mode 100644 BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs create mode 100644 BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs create mode 100644 BrightSharp.NET/Diagrams/VisualExtensions.cs create mode 100644 BrightSharp.NET/Diagrams/ZoomControl.cs create mode 100644 BrightSharp.NET/Extensions/MarkupExtensionProperties.cs create mode 100644 BrightSharp.NET/Extensions/WpfExtensions.cs create mode 100644 BrightSharp.NET/Interop/Constants.cs create mode 100644 BrightSharp.NET/Interop/NativeMethods.cs create mode 100644 BrightSharp.NET/Interop/Structures.cs create mode 100644 BrightSharp.NET/Properties/AssemblyInfo.cs create mode 100644 BrightSharp.NET/Properties/Resources.Designer.cs create mode 100644 BrightSharp.NET/Properties/Resources.resx create mode 100644 BrightSharp.NET/Properties/Settings.Designer.cs create mode 100644 BrightSharp.NET/Properties/Settings.settings create mode 100644 BrightSharp.NET/Themes/Controls/ZoomControl.xaml create mode 100644 BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml create mode 100644 BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml create mode 100644 BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml create mode 100644 BrightSharp.NET/Themes/Generic.xaml create mode 100644 BrightSharp.NET/Themes/Style.Blue.xaml create mode 100644 BrightSharp.NET/Themes/Style.Classic.xaml create mode 100644 BrightSharp.NET/Themes/Style.DarkBlue.xaml create mode 100644 BrightSharp.NET/Themes/Style.DevLab.xaml create mode 100644 BrightSharp.NET/Themes/Style.Silver.xaml create mode 100644 BrightSharp.NET/Themes/Theme.Static.cs create mode 100644 BrightSharp.NET/Themes/Theme.Static.xaml create mode 100644 BrightSharp.NET/Themes/Theme.cs create mode 100644 BrightSharp.NET/Themes/Theme.xaml create mode 100644 BrightSharp.NET/Themes/ThemeManager.cs create mode 100644 BrightSharp.NET/Themes/icons/app.png create mode 100644 BrightSharp.NET/Themes/icons/copy.png create mode 100644 BrightSharp.NET/Themes/icons/cut.png create mode 100644 BrightSharp.NET/Themes/icons/paste.png create mode 100644 BrightSharp.NET/Themes/icons/undo.png create mode 100644 BrightSharp.NET/packages.config diff --git a/BrightSharp.NET/AssemblyInfo.cs b/BrightSharp.NET/AssemblyInfo.cs new file mode 100644 index 0000000..107498e --- /dev/null +++ b/BrightSharp.NET/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; + +[assembly: AssemblyDescription("")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, + ResourceDictionaryLocation.SourceAssembly +)] + +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/developer", "bs")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Extensions")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Behaviors")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Converters")] +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/diagrams", "bsDiag")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/diagrams", "BrightSharp.Diagrams")] diff --git a/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs b/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs new file mode 100644 index 0000000..b0850dd --- /dev/null +++ b/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs @@ -0,0 +1,117 @@ +using Microsoft.Xaml.Behaviors; +using System; +using System.Collections; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Threading; + +namespace BrightSharp.Behaviors +{ + public class FilterDefaultViewTextBoxBehavior : Behavior + { + readonly DispatcherTimer _timer = new DispatcherTimer(); + + public FilterDefaultViewTextBoxBehavior() + { + _timer.Tick += Timer_Tick; + FilterDelay = TimeSpan.FromSeconds(1); + IgnoreCase = null; //Case sensitive if any char upper case + FilterStringPropertyName = "FilterString"; + + } + + + private void Timer_Tick(object sender, EventArgs e) + { + _timer.Stop(); + if (ItemsSource != null) + { + var view = CollectionViewSource.GetDefaultView(ItemsSource); + if (view is ListCollectionView) + { + var listCollectionView = (ListCollectionView)view; + if (listCollectionView.IsAddingNew || listCollectionView.IsEditingItem) return; + } + view.Filter = CustomFilter ?? GetDefaultFilter(ItemsSource.GetType().GetGenericArguments()[0]); + } + } + + public string FilterStringPropertyName { get; set; } + + public bool HasFilterText + { + get { return (bool)GetValue(HasFilterTextProperty); } + set { SetValue(HasFilterTextProperty, value); } + } + + public static readonly DependencyProperty HasFilterTextProperty = + DependencyProperty.Register("HasFilterText", typeof(bool), typeof(FilterDefaultViewTextBoxBehavior), new PropertyMetadata(false)); + + + + public IEnumerable ItemsSource + { + get { return (IEnumerable)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + // Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ItemsSourceProperty = + DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(FilterDefaultViewTextBoxBehavior), new PropertyMetadata(null)); + + + public bool? IgnoreCase { get; set; } + private Predicate GetDefaultFilter(Type filterItemType) + { + Func dataFunc; + var pInfo = filterItemType.GetProperty(FilterStringPropertyName); + if (pInfo == null) + { + dataFunc = (x) => string.Join(",", filterItemType.GetProperties().Where(p => !p.Name.EndsWith("Id")).Select(p => (p.GetValue(x, null) ?? string.Empty).ToString())); + } + else + { + dataFunc = (x) => (pInfo.GetValue(x, null) ?? string.Empty).ToString(); + } + var filterText = AssociatedObject.Text; + var ic = IgnoreCase ?? !filterText.Any(char.IsUpper); + return x => + { + if (x == null || string.IsNullOrEmpty(filterText)) return true; + var propValStr = dataFunc(x); + foreach (var item in filterText.Split(';')) + { + if (propValStr.IndexOf(item, ic ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == -1) + return false; + } + return true; + }; + } + + public Predicate CustomFilter { get; set; } + + public TimeSpan FilterDelay { get { return _timer.Interval; } set { _timer.Interval = value; } } + + protected override void OnAttached() + { + base.OnAttached(); + HasFilterText = !string.IsNullOrEmpty(AssociatedObject.Text); + AssociatedObject.TextChanged += AssociatedObject_TextChanged; + } + + private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) + { + _timer.Stop(); _timer.Start(); + HasFilterText = !string.IsNullOrEmpty(AssociatedObject.Text); + } + + protected override void OnDetaching() + { + AssociatedObject.TextChanged -= AssociatedObject_TextChanged; + _timer.Tick -= Timer_Tick; + base.OnDetaching(); + } + } +} diff --git a/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs b/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs new file mode 100644 index 0000000..eba48ce --- /dev/null +++ b/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs @@ -0,0 +1,80 @@ +using BrightSharp.Interop; +using BrightSharp.Interop.Constants; +using BrightSharp.Interop.Structures; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace BrightSharp.Behaviors +{ + internal class MinMaxSize_Logic + { + private HwndSource hwndSource; + private Window associatedObject; + public MinMaxSize_Logic(Window associatedObject) + { + this.associatedObject = associatedObject; + } + public void OnAttached() + { + this.associatedObject.SourceInitialized += AssociatedObject_SourceInitialized; + } + + private void AssociatedObject_SourceInitialized(object sender, EventArgs e) + { + IntPtr handle = new WindowInteropHelper(this.associatedObject).Handle; + hwndSource = HwndSource.FromHwnd(handle); + hwndSource.AddHook(WindowProc); + } + + public void OnDetaching() + { + this.associatedObject.SourceInitialized -= AssociatedObject_SourceInitialized; + if (hwndSource != null) + { + hwndSource.RemoveHook(WindowProc); + hwndSource.Dispose(); + } + } + + [DebuggerStepThrough] + private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + switch (msg) + { + case 0x0024: + WmGetMinMaxInfo(hwnd, lParam); + handled = true; + break; + } + return (IntPtr)0; + } + + private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam) + { + var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); + + // Adjust the maximized size and position to fit the work area of the correct monitor + IntPtr monitor = NativeMethods.MonitorFromWindow(hwnd, (int)MonitorFromWindowFlags.MONITOR_DEFAULTTONEAREST); + + if (monitor != IntPtr.Zero) + { + var monitorInfo = new MONITORINFO(); + NativeMethods.GetMonitorInfo(monitor, monitorInfo); + RECT rcWorkArea = monitorInfo.rcWork; + RECT rcMonitorArea = monitorInfo.rcMonitor; + mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left); + mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top); + mmi.ptMaxSize.x = Math.Abs(rcWorkArea.Right - rcWorkArea.Left); + mmi.ptMaxSize.y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top); + mmi.ptMinTrackSize.x = (int)associatedObject.MinWidth; + mmi.ptMinTrackSize.y = (int)associatedObject.MinHeight; + } + + Marshal.StructureToPtr(mmi, lParam, true); + } + + } +} diff --git a/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs b/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs new file mode 100644 index 0000000..51cfaff --- /dev/null +++ b/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs @@ -0,0 +1,33 @@ +using Microsoft.Xaml.Behaviors; +using System.Windows.Controls.Primitives; +using System.Windows.Input; + +namespace BrightSharp.Behaviors +{ + public class SelectAllTextOnFocusBehavior : Behavior + { + protected override void OnAttached() { + base.OnAttached(); + AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus; + AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown; + } + + protected override void OnDetaching() { + base.OnDetaching(); + AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus; + AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown; + } + + private void AssociatedObjectGotKeyboardFocus(object sender, + KeyboardFocusChangedEventArgs e) { + AssociatedObject.SelectAll(); + } + + private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { + if (!AssociatedObject.IsKeyboardFocusWithin) { + AssociatedObject.Focus(); + e.Handled = true; + } + } + } +} diff --git a/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs b/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs new file mode 100644 index 0000000..90b9da7 --- /dev/null +++ b/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs @@ -0,0 +1,23 @@ +using Microsoft.Xaml.Behaviors; +using System.Windows; + +namespace BrightSharp.Behaviors +{ + public class WindowMinMaxSizeBehavior : Behavior + { + private MinMaxSize_Logic _logic; + protected override void OnAttached() + { + base.OnAttached(); + _logic = new MinMaxSize_Logic(AssociatedObject); + _logic.OnAttached(); + } + + + protected override void OnDetaching() + { + _logic.OnDetaching(); + base.OnDetaching(); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs b/BrightSharp.NET/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs new file mode 100644 index 0000000..f78a141 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Behaviors/FilterDefaultViewTextBoxBehavior.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Interactivity; +using System.Windows.Threading; + +namespace BrightSharp.Behaviors +{ + public class FilterDefaultViewTextBoxBehavior : Behavior + { + readonly DispatcherTimer _timer = new DispatcherTimer(); + + public FilterDefaultViewTextBoxBehavior() + { + _timer.Tick += Timer_Tick; + FilterDelay = TimeSpan.FromSeconds(1); + IgnoreCase = null; //Case sensitive if any char upper case + FilterStringPropertyName = "FilterString"; + + } + + + private void Timer_Tick(object sender, EventArgs e) + { + _timer.Stop(); + if (ItemsSource != null) + { + var view = CollectionViewSource.GetDefaultView(ItemsSource); + if (view is ListCollectionView) + { + var listCollectionView = (ListCollectionView)view; + if (listCollectionView.IsAddingNew || listCollectionView.IsEditingItem) return; + } + view.Filter = CustomFilter ?? GetDefaultFilter(ItemsSource.GetType().GetGenericArguments()[0]); + } + } + + public string FilterStringPropertyName { get; set; } + + public bool HasFilterText + { + get { return (bool)GetValue(HasFilterTextProperty); } + set { SetValue(HasFilterTextProperty, value); } + } + + public static readonly DependencyProperty HasFilterTextProperty = + DependencyProperty.Register("HasFilterText", typeof(bool), typeof(FilterDefaultViewTextBoxBehavior), new PropertyMetadata(false)); + + + + public IEnumerable ItemsSource + { + get { return (IEnumerable)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + // Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ItemsSourceProperty = + DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(FilterDefaultViewTextBoxBehavior), new PropertyMetadata(null)); + + + public bool? IgnoreCase { get; set; } + private Predicate GetDefaultFilter(Type filterItemType) + { + Func dataFunc; + var pInfo = filterItemType.GetProperty(FilterStringPropertyName); + if (pInfo == null) + { + dataFunc = (x) => string.Join(",", filterItemType.GetProperties().Where(p => !p.Name.EndsWith("Id")).Select(p => (p.GetValue(x, null) ?? string.Empty).ToString())); + } + else + { + dataFunc = (x) => (pInfo.GetValue(x, null) ?? string.Empty).ToString(); + } + var filterText = AssociatedObject.Text; + var ic = IgnoreCase ?? !filterText.Any(char.IsUpper); + return x => + { + if (x == null || string.IsNullOrEmpty(filterText)) return true; + var propValStr = dataFunc(x); + foreach (var item in filterText.Split(';')) + { + if (propValStr.IndexOf(item, ic ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) == -1) + return false; + } + return true; + }; + } + + public Predicate CustomFilter { get; set; } + + public TimeSpan FilterDelay { get { return _timer.Interval; } set { _timer.Interval = value; } } + + protected override void OnAttached() + { + base.OnAttached(); + HasFilterText = !string.IsNullOrEmpty(AssociatedObject.Text); + AssociatedObject.TextChanged += AssociatedObject_TextChanged; + } + + private void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e) + { + _timer.Stop(); _timer.Start(); + HasFilterText = !string.IsNullOrEmpty(AssociatedObject.Text); + } + + protected override void OnDetaching() + { + AssociatedObject.TextChanged -= AssociatedObject_TextChanged; + _timer.Tick -= Timer_Tick; + base.OnDetaching(); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs b/BrightSharp.NET/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs new file mode 100644 index 0000000..eba48ce --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Behaviors/MinMaxSize_Logic.cs @@ -0,0 +1,80 @@ +using BrightSharp.Interop; +using BrightSharp.Interop.Constants; +using BrightSharp.Interop.Structures; +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace BrightSharp.Behaviors +{ + internal class MinMaxSize_Logic + { + private HwndSource hwndSource; + private Window associatedObject; + public MinMaxSize_Logic(Window associatedObject) + { + this.associatedObject = associatedObject; + } + public void OnAttached() + { + this.associatedObject.SourceInitialized += AssociatedObject_SourceInitialized; + } + + private void AssociatedObject_SourceInitialized(object sender, EventArgs e) + { + IntPtr handle = new WindowInteropHelper(this.associatedObject).Handle; + hwndSource = HwndSource.FromHwnd(handle); + hwndSource.AddHook(WindowProc); + } + + public void OnDetaching() + { + this.associatedObject.SourceInitialized -= AssociatedObject_SourceInitialized; + if (hwndSource != null) + { + hwndSource.RemoveHook(WindowProc); + hwndSource.Dispose(); + } + } + + [DebuggerStepThrough] + private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + switch (msg) + { + case 0x0024: + WmGetMinMaxInfo(hwnd, lParam); + handled = true; + break; + } + return (IntPtr)0; + } + + private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam) + { + var mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); + + // Adjust the maximized size and position to fit the work area of the correct monitor + IntPtr monitor = NativeMethods.MonitorFromWindow(hwnd, (int)MonitorFromWindowFlags.MONITOR_DEFAULTTONEAREST); + + if (monitor != IntPtr.Zero) + { + var monitorInfo = new MONITORINFO(); + NativeMethods.GetMonitorInfo(monitor, monitorInfo); + RECT rcWorkArea = monitorInfo.rcWork; + RECT rcMonitorArea = monitorInfo.rcMonitor; + mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left); + mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top); + mmi.ptMaxSize.x = Math.Abs(rcWorkArea.Right - rcWorkArea.Left); + mmi.ptMaxSize.y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top); + mmi.ptMinTrackSize.x = (int)associatedObject.MinWidth; + mmi.ptMinTrackSize.y = (int)associatedObject.MinHeight; + } + + Marshal.StructureToPtr(mmi, lParam, true); + } + + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs b/BrightSharp.NET/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs new file mode 100644 index 0000000..74192bd --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Behaviors/SelectAllTextOnFocusBehavior.cs @@ -0,0 +1,33 @@ +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Interactivity; + +namespace BrightSharp.Behaviors +{ + public class SelectAllTextOnFocusBehavior : Behavior + { + protected override void OnAttached() { + base.OnAttached(); + AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus; + AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown; + } + + protected override void OnDetaching() { + base.OnDetaching(); + AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus; + AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown; + } + + private void AssociatedObjectGotKeyboardFocus(object sender, + KeyboardFocusChangedEventArgs e) { + AssociatedObject.SelectAll(); + } + + private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { + if (!AssociatedObject.IsKeyboardFocusWithin) { + AssociatedObject.Focus(); + e.Handled = true; + } + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs b/BrightSharp.NET/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs new file mode 100644 index 0000000..04d7b98 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Behaviors/WindowMinMaxSizeBehavior.cs @@ -0,0 +1,23 @@ +using System.Windows; +using System.Windows.Interactivity; + +namespace BrightSharp.Behaviors +{ + public class WindowMinMaxSizeBehavior : Behavior + { + private MinMaxSize_Logic _logic; + protected override void OnAttached() + { + base.OnAttached(); + _logic = new MinMaxSize_Logic(AssociatedObject); + _logic.OnAttached(); + } + + + protected override void OnDetaching() + { + _logic.OnDetaching(); + base.OnDetaching(); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/BrightSharp.NET.csproj b/BrightSharp.NET/BrightSharp.NET/BrightSharp.NET.csproj new file mode 100644 index 0000000..6dffab7 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/BrightSharp.NET.csproj @@ -0,0 +1,170 @@ + + + + + Debug + AnyCPU + {E6D5870A-A71E-47C1-9D5F-1E49CB4F6D4C} + Library + BrightSharp + BrightSharp + v4.7.2 + 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\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\Microsoft.Expression.Interactions.dll + + + + + ..\..\..\..\packages\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\System.Windows.Interactivity.dll + + + + + + + + + 4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Commands/AsyncCommand.cs b/BrightSharp.NET/BrightSharp.NET/Commands/AsyncCommand.cs new file mode 100644 index 0000000..400cab1 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Commands/AsyncCommand.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace BrightSharp.Commands +{ + public class AsyncCommand : ICommand + { + private readonly Func _execute; + private readonly Func _canExecute; + private Action _onComplete; + private Action _onFail; + private bool _isExecuting; + + public AsyncCommand(Func execute) : this(p => execute?.Invoke()) + { + } + + public AsyncCommand(Func execute) : this(execute, o => true) + { + } + + public AsyncCommand(Func execute, Func canExecute) + { + _execute = execute; + _canExecute = canExecute; + } + + public AsyncCommand OnComplete(Action onComplete) + { + _onComplete = onComplete; + return this; + } + public AsyncCommand OnFail(Action onFail) + { + _onFail = onFail; + return this; + } + + public bool CanExecute(object parameter) + { + return !_isExecuting && _canExecute(parameter); + } + + public event EventHandler CanExecuteChanged; + + public async void Execute(object parameter) + { + _isExecuting = true; + OnCanExecuteChanged(); + try + { + await _execute(parameter); + _onComplete?.Invoke(); + } + catch (Exception ex) + { + while (ex.InnerException != null) + ex = ex.InnerException; + _onFail?.Invoke(ex); + } + finally + { + _isExecuting = false; + OnCanExecuteChanged(); + } + } + + public virtual void OnCanExecuteChanged() + { + CanExecuteChanged?.Invoke(this, new EventArgs()); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Commands/RelayCommand.cs b/BrightSharp.NET/BrightSharp.NET/Commands/RelayCommand.cs new file mode 100644 index 0000000..1c13498 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Commands/RelayCommand.cs @@ -0,0 +1,71 @@ +using System; +using System.Windows.Input; + +namespace BrightSharp.Commands +{ + public class RelayCommand : ICommand + { + private readonly Action _methodToExecute; + private readonly Action _methodToExecuteWithParam; + private readonly Func _canExecuteEvaluator; + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public RelayCommand(Action methodToExecute, Func canExecuteEvaluator = null) + { + _methodToExecuteWithParam = methodToExecute; + _canExecuteEvaluator = canExecuteEvaluator; + } + + public RelayCommand(Action methodToExecute) + { + _methodToExecute = methodToExecute; + } + + public bool CanExecute(object parameter) + { + if (_canExecuteEvaluator == null) + return true; + else + return _canExecuteEvaluator.Invoke(parameter); + } + public void Execute(object parameter) + { + _methodToExecuteWithParam?.Invoke(parameter); + _methodToExecute?.Invoke(); + } + } + + public class RelayCommand : ICommand where T : class + { + private readonly Action _methodToExecuteWithParam; + private readonly Func _canExecuteEvaluator; + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public RelayCommand(Action methodToExecute, Func canExecuteEvaluator = null) + { + _methodToExecuteWithParam = methodToExecute; + _canExecuteEvaluator = canExecuteEvaluator; + } + + public bool CanExecute(object parameter) + { + if (_canExecuteEvaluator == null) + return true; + return _canExecuteEvaluator.Invoke(parameter as T); + } + public void Execute(object parameter) + { + _methodToExecuteWithParam?.Invoke(parameter as T); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Converters/IntToValueConverter.cs b/BrightSharp.NET/BrightSharp.NET/Converters/IntToValueConverter.cs new file mode 100644 index 0000000..514a350 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Converters/IntToValueConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.Globalization; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + public class IntToValueConverter : IValueConverter + { + public ulong? TrueValueInt { get; set; } = null; + public ulong? FalseValueInt { get; set; } = 0; + + + public object TrueValue { get; set; } = true; + public object FalseValue { get; set; } = false; + + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + { + value = false; + } + if (value is string valueStr) + { + value = valueStr.Length > 0; + } + if (value is bool valueBool) + { + value = valueBool ? 1 : 0; + } + if (value is ICollection valueCol) + { + value = valueCol.Count; + } + if (value is Enum en) + { + value = System.Convert.ToInt32(en); + } + if (ulong.TryParse(value.ToString(), out ulong valueLong)) + { + // Exact match for false + if (FalseValueInt.HasValue && FalseValueInt == valueLong) return FalseValue; + // Exact match for true + if (TrueValueInt.HasValue && TrueValueInt == valueLong) return TrueValue; + // Any value for false + if (!FalseValueInt.HasValue) return FalseValue; + // Any value for true + if (!TrueValueInt.HasValue) return TrueValue; + } + return TrueValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + // Convert with potential lose exact value match + return Equals(value, TrueValue) ? TrueValueInt : FalseValueInt; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs b/BrightSharp.NET/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs new file mode 100644 index 0000000..9f4bcfc --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + [Localizability(LocalizationCategory.NeverLocalize)] + public class InverseBooleanToVisibilityConverter : IValueConverter + { + private BooleanToVisibilityConverter _converter = new BooleanToVisibilityConverter(); + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { + var result = _converter.Convert(value, targetType, parameter, culture) as Visibility?; + return result == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { + var result = _converter.ConvertBack(value, targetType, parameter, culture) as bool?; + return result == true ? false : true; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Converters/ThicknessConverter.cs b/BrightSharp.NET/BrightSharp.NET/Converters/ThicknessConverter.cs new file mode 100644 index 0000000..198b7c5 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Converters/ThicknessConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + internal class ThicknessConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is Thickness) + { + var offset = double.Parse(parameter.ToString(), CultureInfo.InvariantCulture.NumberFormat); + var thick = (Thickness)value; + + return new Thickness(Math.Max(0, thick.Left + offset), + Math.Max(0, thick.Top + offset), + Math.Max(0, thick.Right + offset), + Math.Max(0, thick.Bottom + offset)); + } + else if(value is CornerRadius) + { + var offset = double.Parse(parameter.ToString(), CultureInfo.InvariantCulture.NumberFormat); + var thick = (CornerRadius)value; + + return new CornerRadius(Math.Max(0, thick.TopLeft + offset), + Math.Max(0, thick.TopRight + offset), + Math.Max(0, thick.BottomRight + offset), + Math.Max(0, thick.BottomLeft + offset)); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs new file mode 100644 index 0000000..343b2d6 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs @@ -0,0 +1,48 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeRotateAdorner : Adorner + { + private VisualCollection visuals; + private ResizeRotateChrome chrome; + + protected override int VisualChildrenCount + { + get + { + return visuals.Count; + } + } + + public ResizeRotateAdorner(ContentControl designerItem) + : base(designerItem) + { + SnapsToDevicePixels = true; + chrome = new ResizeRotateChrome(); + chrome.DataContext = designerItem; + visuals = new VisualCollection(this); + visuals.Add(chrome); + Focusable = true; + } + + + + protected override Size ArrangeOverride(Size arrangeBounds) + { + chrome.Arrange(new Rect(arrangeBounds)); + return arrangeBounds; + } + + protected override Visual GetVisualChild(int index) + { + return visuals[index]; + } + + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs new file mode 100644 index 0000000..7f60b09 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeRotateChrome : Control + { + static ResizeRotateChrome() + { + FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(ResizeRotateChrome), new FrameworkPropertyMetadata(typeof(ResizeRotateChrome))); + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs new file mode 100644 index 0000000..9c68a88 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class SizeAdorner : Adorner + { + private SizeChrome chrome; + private VisualCollection visuals; + private FrameworkElement designerItem; + + protected override int VisualChildrenCount + { + get + { + return visuals.Count; + } + } + + public SizeAdorner(FrameworkElement designerItem) + : base(designerItem) + { + SnapsToDevicePixels = true; + this.designerItem = designerItem; + chrome = new SizeChrome(); + chrome.DataContext = designerItem; + visuals = new VisualCollection(this); + visuals.Add(chrome); + } + + protected override Visual GetVisualChild(int index) + { + return visuals[index]; + } + + protected override Size ArrangeOverride(Size arrangeBounds) + { + chrome.Arrange(new Rect(new Point(0.0, 0.0), arrangeBounds)); + return arrangeBounds; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs new file mode 100644 index 0000000..1160a92 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs @@ -0,0 +1,34 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace BrightSharp.Diagrams +{ + + [ToolboxItem(false)] + public class SizeChrome : Control + { + static SizeChrome() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SizeChrome), new FrameworkPropertyMetadata(typeof(SizeChrome))); + } + } + + public class DoubleFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + double d = (double)value; + if (double.IsNaN(d)) return "(Auto)"; + return Math.Round(d); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs new file mode 100644 index 0000000..918d9b4 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs @@ -0,0 +1,103 @@ +using System; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.ComponentModel; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class DesignerItemDecorator : Control + { + private Adorner adorner; + + public bool ShowDecorator + { + get { return (bool)GetValue(ShowDecoratorProperty); } + set { SetValue(ShowDecoratorProperty, value); } + } + + public static readonly DependencyProperty ShowDecoratorProperty = + DependencyProperty.Register("ShowDecorator", typeof(bool), typeof(DesignerItemDecorator), + new FrameworkPropertyMetadata(false, new PropertyChangedCallback(ShowDecoratorProperty_Changed))); + + public DesignerItemDecorator() + { + Unloaded += new RoutedEventHandler(DesignerItemDecorator_Unloaded); + } + + private void HideAdorner() + { + if (adorner != null) + { + adorner.Visibility = Visibility.Hidden; + } + } + + private void ShowAdorner() + { + if (adorner == null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); + + if (adornerLayer != null) + { + ContentControl designerItem = DataContext as ContentControl; + Canvas canvas = VisualTreeHelper.GetParent(designerItem) as Canvas; + adorner = new ResizeRotateAdorner(designerItem); + adornerLayer.Add(adorner); + + if (ShowDecorator) + { + adorner.Visibility = Visibility.Visible; + + var anim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(.2)); + adorner.BeginAnimation(OpacityProperty, anim); + } + else + { + adorner.Visibility = Visibility.Hidden; + } + } + } + else + { + adorner.Visibility = Visibility.Visible; + + var anim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(.2)); + adorner.BeginAnimation(OpacityProperty, anim); + } + } + + private void DesignerItemDecorator_Unloaded(object sender, RoutedEventArgs e) + { + if (adorner != null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); + if (adornerLayer != null) + { + adornerLayer.Remove(adorner); + } + + adorner = null; + } + } + + private static void ShowDecoratorProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + DesignerItemDecorator decorator = (DesignerItemDecorator)d; + bool showDecorator = (bool)e.NewValue; + + if (showDecorator) + { + decorator.ShowAdorner(); + } + else + { + decorator.HideAdorner(); + } + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/SelectionBehavior.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/SelectionBehavior.cs new file mode 100644 index 0000000..a1ed199 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/SelectionBehavior.cs @@ -0,0 +1,96 @@ +using BrightSharp.Extensions; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace BrightSharp.Diagrams +{ + public static class SelectionBehavior + { + public static void Attach(FrameworkElement fe) + { + FrameworkElement selectedControl = null; + Style designerStyle = (Style)Application.Current.FindResource("DesignerItemStyle"); + if (fe is Panel) + { + var fePanel = (Panel)fe; + fe.PreviewMouseLeftButtonDown += (s, e) => + { + if (e.Source is DependencyObject) + { + var clickedElement = ((DependencyObject)e.OriginalSource).GetAncestors().FirstOrDefault(el => el.Style == designerStyle && WpfExtensions.GetItemsPanel(el.GetParent(true)) == fe); + if (clickedElement == null) + { + foreach (DependencyObject item in fePanel.Children) + { + Selector.SetIsSelected(item, false); + } + selectedControl = null; + return; + } + foreach (var control in fePanel.Children.OfType()) + { + if (ProcessControl(control, clickedElement, ref selectedControl)) + { + if (selectedControl is ContentControl cc && cc.Content is ButtonBase) + { + e.Handled = true; + return; + } + } + } + + } + }; + } + else if (fe is ItemsControl) + { + var feItemsControl = (ItemsControl)fe; + fe.PreviewMouseLeftButtonDown += (s, e) => + { + if (e.Source is DependencyObject) + { + var clickedElement = ((DependencyObject)e.Source).GetAncestors().FirstOrDefault(el => el.Style == designerStyle && el.Parent == fe); + if (clickedElement == null) + { + foreach (DependencyObject item in feItemsControl.Items) + { + Selector.SetIsSelected(item, false); + } + selectedControl = null; + return; + } + foreach (var control in feItemsControl.Items.OfType()) + { + if (ProcessControl(control, clickedElement, ref selectedControl)) + { + if (selectedControl is ContentControl cc && cc.Content is ButtonBase) + { + e.Handled = true; + return; + } + } + } + + } + }; + } + } + + private static bool ProcessControl(FrameworkElement control, FrameworkElement clickedElement, ref FrameworkElement selectedControl) + { + if (control == clickedElement && control != selectedControl) + { + if (selectedControl != null) + { + Selector.SetIsSelected(selectedControl, false); + } + Selector.SetIsSelected(control, true); + selectedControl = control; + return true; + } + return false; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs new file mode 100644 index 0000000..e935e94 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class MoveThumb : Thumb + { + private RotateTransform rotateTransform; + private FrameworkElement designerItem; + private static int? zIndex = null; + + public MoveThumb() + { + DragStarted += MoveThumb_DragStarted; + DragDelta += MoveThumb_DragDelta; + DragCompleted += MoveThumb_DragCompleted; + } + + private void MoveThumb_DragCompleted(object sender, DragCompletedEventArgs e) + { + //TODO Need think about ZIndex changes + } + + private void MoveThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as FrameworkElement; + + if (designerItem != null) + { + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (designerItem.GetBindingExpression(Panel.ZIndexProperty) == null) + { + zIndex = Math.Max(zIndex ?? 0, Panel.GetZIndex(designerItem)); + Panel.SetZIndex(designerItem, zIndex.Value + 1); + } + } + } + + private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null) + { + Point dragDelta = new Point(e.HorizontalChange, e.VerticalChange); + + double gridSize = 0; + + var zoomControl = designerItem.Parent as ZoomControl; + if (zoomControl != null) gridSize = zoomControl.GridSize; + + if (rotateTransform != null) + { + dragDelta = rotateTransform.Transform(dragDelta); + } + if (double.IsNaN(Canvas.GetLeft(designerItem))) Canvas.SetLeft(designerItem, 0); + if (double.IsNaN(Canvas.GetTop(designerItem))) Canvas.SetTop(designerItem, 0); + + var newLeft = Canvas.GetLeft(designerItem) + dragDelta.X; + var newTop = Canvas.GetTop(designerItem) + dragDelta.Y; + if (gridSize > 0) + { + newLeft = Math.Truncate(newLeft / gridSize) * gridSize; + newTop = Math.Truncate(newTop / gridSize) * gridSize; + } + Canvas.SetLeft(designerItem, newLeft); + Canvas.SetTop(designerItem, newTop); + + } + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs new file mode 100644 index 0000000..4db4666 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs @@ -0,0 +1,160 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Media; +using System.Windows.Input; +using System.ComponentModel; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeThumb : Thumb + { + private RotateTransform rotateTransform; + private double angle; + private Adorner adorner; + private Point transformOrigin; + private FrameworkElement designerItem; + private FrameworkElement canvas; + + public ResizeThumb() + { + DragStarted += new DragStartedEventHandler(ResizeThumb_DragStarted); + DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta); + DragCompleted += new DragCompletedEventHandler(ResizeThumb_DragCompleted); + MouseRightButtonDown += new MouseButtonEventHandler(ResizeThumb_MouseRightButtonDown); + } + + private void ResizeThumb_MouseRightButtonDown(object sender, MouseButtonEventArgs e) + { + designerItem = designerItem ?? DataContext as FrameworkElement; + + if (VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom) + { + designerItem.Height = double.NaN; + } + if (HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right) + { + designerItem.Width = double.NaN; + } + } + + private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as ContentControl; + + if (designerItem != null) + { + canvas = VisualTreeHelper.GetParent(designerItem) as FrameworkElement; + + if (canvas != null) + { + transformOrigin = designerItem.RenderTransformOrigin; + + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform != null) + { + angle = rotateTransform.Angle * Math.PI / 180.0; + } + else + { + angle = 0.0d; + } + + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas); + if (adornerLayer != null) + { + adorner = new SizeAdorner(designerItem); + adornerLayer.Add(adorner); + } + } + } + } + + private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null) + { + double deltaVertical, deltaHorizontal; + if (double.IsNaN(Canvas.GetTop(designerItem))) Canvas.SetTop(designerItem, 0); + if (double.IsNaN(Canvas.GetLeft(designerItem))) Canvas.SetLeft(designerItem, 0); + if ((VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom) && double.IsNaN(designerItem.Height)) designerItem.Height = designerItem.ActualHeight; + if ((HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right) && double.IsNaN(designerItem.Width)) designerItem.Width = designerItem.ActualWidth; + + var zoomControl = designerItem.Parent as dynamic; + double.TryParse(zoomControl.Tag as string, out var gridSize); + + var verticalChange = e.VerticalChange; + var horizontalChange = e.HorizontalChange; + + if (gridSize > 0) + { + verticalChange = Math.Truncate(verticalChange / gridSize) * gridSize; + horizontalChange = Math.Truncate(horizontalChange / gridSize) * gridSize; + } + if (verticalChange != 0) + { + switch (VerticalAlignment) + { + case System.Windows.VerticalAlignment.Bottom: + deltaVertical = Math.Min(-verticalChange, designerItem.ActualHeight - designerItem.MinHeight); + deltaVertical = Math.Max(deltaVertical, designerItem.ActualHeight - designerItem.MaxHeight); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle)))); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) - deltaVertical * transformOrigin.Y * Math.Sin(-angle)); + designerItem.Height -= deltaVertical; + break; + case System.Windows.VerticalAlignment.Top: + deltaVertical = Math.Min(verticalChange, designerItem.ActualHeight - designerItem.MinHeight); + deltaVertical = Math.Max(deltaVertical, designerItem.ActualHeight - designerItem.MaxHeight); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical * Math.Cos(-angle) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle)))); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaVertical * Math.Sin(-angle) - (transformOrigin.Y * deltaVertical * Math.Sin(-angle))); + designerItem.Height -= deltaVertical; + break; + default: + break; + } + } + if (horizontalChange != 0) + { + switch (HorizontalAlignment) + { + case System.Windows.HorizontalAlignment.Left: + deltaHorizontal = Math.Min(horizontalChange, designerItem.ActualWidth - designerItem.MinWidth); + deltaHorizontal = Math.Max(deltaHorizontal, designerItem.ActualWidth - designerItem.MaxWidth); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaHorizontal * Math.Sin(angle) - transformOrigin.X * deltaHorizontal * Math.Sin(angle)); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal * Math.Cos(angle) + (transformOrigin.X * deltaHorizontal * (1 - Math.Cos(angle)))); + designerItem.Width -= deltaHorizontal; + break; + case System.Windows.HorizontalAlignment.Right: + deltaHorizontal = Math.Min(-horizontalChange, designerItem.ActualWidth - designerItem.MinWidth); + deltaHorizontal = Math.Max(deltaHorizontal, designerItem.ActualWidth - designerItem.MaxWidth); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) - transformOrigin.X * deltaHorizontal * Math.Sin(angle)); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + (deltaHorizontal * transformOrigin.X * (1 - Math.Cos(angle)))); + designerItem.Width -= deltaHorizontal; + break; + default: + break; + } + } + } + + e.Handled = true; + } + + private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e) + { + if (adorner != null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas); + if (adornerLayer != null) + { + adornerLayer.Remove(adorner); + } + + adorner = null; + } + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs new file mode 100644 index 0000000..1edb7ac --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs @@ -0,0 +1,88 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class RotateThumb : Thumb + { + private double initialAngle; + private RotateTransform rotateTransform; + private Vector startVector; + private Point centerPoint; + private ContentControl designerItem; + private Canvas canvas; + + public RotateThumb() + { + DragDelta += new DragDeltaEventHandler(RotateThumb_DragDelta); + DragStarted += new DragStartedEventHandler(RotateThumb_DragStarted); + MouseRightButtonDown += RotateThumb_MouseLeftButtonDown; + } + + private void RotateThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.RightButton == MouseButtonState.Pressed) + { + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform != null) + { + rotateTransform.Angle = 0; + designerItem.InvalidateMeasure(); + } + } + } + + private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as ContentControl; + + if (designerItem != null) + { + canvas = VisualTreeHelper.GetParent(designerItem) as Canvas; + + if (canvas != null) + { + centerPoint = designerItem.TranslatePoint( + new Point(designerItem.ActualWidth * designerItem.RenderTransformOrigin.X, + designerItem.ActualHeight * designerItem.RenderTransformOrigin.Y), + canvas); + + Point startPoint = Mouse.GetPosition(canvas); + startVector = Point.Subtract(startPoint, centerPoint); + + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform == null) + { + designerItem.RenderTransform = new RotateTransform(0); + initialAngle = 0; + } + else + { + initialAngle = rotateTransform.Angle; + } + } + } + } + + private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null && canvas != null) + { + Point currentPoint = Mouse.GetPosition(canvas); + Vector deltaVector = Point.Subtract(currentPoint, centerPoint); + + double angle = Vector.AngleBetween(startVector, deltaVector); + + RotateTransform rotateTransform = designerItem.RenderTransform as RotateTransform; + rotateTransform.Angle = initialAngle + Math.Round(angle, 0); + designerItem.InvalidateMeasure(); + } + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/VisualExtensions.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/VisualExtensions.cs new file mode 100644 index 0000000..e30c652 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/VisualExtensions.cs @@ -0,0 +1,132 @@ +using BrightSharp.Extensions; +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Animation; + +namespace BrightSharp.Diagrams +{ + /// + /// If starts with a(A) then use animation, + /// $FromZoom-$ToZoom pattern + /// + public class VisualExtensions : DependencyObject + { + #region LevelOfDetails Attached Property + + public static readonly DependencyProperty LODZoomProperty = + DependencyProperty.RegisterAttached("LODZoom", + typeof(string), + typeof(VisualExtensions), + new UIPropertyMetadata(null, OnChangeLODZoomProperty)); + + public static void SetLODZoom(UIElement element, string o) + { + element.SetValue(LODZoomProperty, o); + } + + public static string GetLODZoom(UIElement element) + { + return (string)element.GetValue(LODZoomProperty); + } + #endregion + + public static bool GetCanRotate(DependencyObject obj) { + return (bool)obj.GetValue(CanRotateProperty); + } + + public static void SetCanRotate(DependencyObject obj, bool value) { + obj.SetValue(CanRotateProperty, value); + } + + public static readonly DependencyProperty CanRotateProperty = + DependencyProperty.RegisterAttached("CanRotate", typeof(bool), typeof(VisualExtensions), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + private static void OnChangeLODZoomProperty(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = d as FrameworkElement; + if (element == null) return; + + var window = Window.GetWindow(element); + if (window == null) return; + + if (e.NewValue != e.OldValue) + { + var zoomControl = element.FindAncestor(); + if (zoomControl == null) return; + + var zoomChangedHandler = new RoutedEventHandler((sender, args) => + { + try { + ChangeVisibility(args, element, window); + } + catch (Exception) { + } + }); + + + if (string.IsNullOrWhiteSpace((string)e.NewValue)) + { + element.Opacity = 1; + zoomControl.ZoomChanged -= zoomChangedHandler; + zoomControl.Loaded -= zoomChangedHandler; + } + else + { + zoomControl.ZoomChanged += zoomChangedHandler; + zoomControl.Loaded += zoomChangedHandler; + } + } + } + + private static void ChangeVisibility(RoutedEventArgs args, FrameworkElement element, Window window) { + var lodInfo = new LodInfo(GetLODZoom(element)); + + var transform = element.TransformToVisual(window) as MatrixTransform; + var scaleX = transform.Matrix.M11; + + var newOpacity = (scaleX >= lodInfo.StartRange && scaleX <= lodInfo.EndRange) ? 1 : 0; + + if (lodInfo.UseAnimation && args.RoutedEvent != FrameworkElement.LoadedEvent) { + element.Visibility = Visibility.Visible; + var animation = new DoubleAnimation(newOpacity, TimeSpan.FromSeconds(.5)); + element.BeginAnimation(UIElement.OpacityProperty, animation); + } + else { + element.Visibility = newOpacity == 1 ? Visibility.Visible : Visibility.Hidden; + element.Opacity = newOpacity; + } + } + + sealed class LodInfo + { + public LodInfo(string lod) + { + lod = lod.TrimStart(); + UseAnimation = lod.StartsWith("a", true, CultureInfo.InvariantCulture); + lod = lod.TrimStart('a', 'A').Trim(); + + double rangeStart = 0; + double rangeEnd = double.PositiveInfinity; + var vals = lod.Split('-'); + + double.TryParse(vals[0], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rangeStart); + + if (vals.Length > 1) + { + if (!double.TryParse(vals[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rangeEnd)) + { + rangeEnd = double.PositiveInfinity; + } + } + EndRange = rangeEnd; + StartRange = rangeStart; + } + public double StartRange { get; set; } + public double EndRange { get; set; } + public bool UseAnimation { get; set; } + } + } + +} diff --git a/BrightSharp.NET/BrightSharp.NET/Diagrams/ZoomControl.cs b/BrightSharp.NET/BrightSharp.NET/Diagrams/ZoomControl.cs new file mode 100644 index 0000000..287d689 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Diagrams/ZoomControl.cs @@ -0,0 +1,228 @@ +using BrightSharp.Extensions; +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media.Animation; + +namespace BrightSharp.Diagrams +{ + + public partial class ZoomControl : ItemsControl + { + public ZoomControl() + { + Loaded += ZoomControl_Loaded; + + } + + private void ZoomControl_Loaded(object sender, RoutedEventArgs e) + { + SelectionBehavior.Attach(this); + } + + public ContentControl SelectedControl + { + get { return (ContentControl)GetValue(SelectedControlProperty); } + set { SetValue(SelectedControlProperty, value); } + } + + public static readonly DependencyProperty SelectedControlProperty = + DependencyProperty.Register("SelectedControl", typeof(ContentControl), typeof(ZoomControl), new PropertyMetadata(null)); + + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); + + if (e.MiddleButton == MouseButtonState.Pressed) + { + _panPoint = e.GetPosition(this); + } + } + + private Point? _panPoint; + + #region Props + + public double TranslateX + { + get { return (double)GetValue(TranslateXProperty); } + set { SetValue(TranslateXProperty, value); } + } + + public static readonly DependencyProperty TranslateXProperty = + DependencyProperty.Register("TranslateX", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange, TranslateChangedHandler)); + + + + public double TranslateY + { + get { return (double)GetValue(TranslateYProperty); } + set { SetValue(TranslateYProperty, value); } + } + + public static readonly DependencyProperty TranslateYProperty = + DependencyProperty.Register("TranslateY", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange, TranslateChangedHandler)); + + + + public double GridSize + { + get { return (double)GetValue(GridSizeProperty); } + set { SetValue(GridSizeProperty, value); } + } + + public static readonly DependencyProperty GridSizeProperty = + DependencyProperty.Register("GridSize", typeof(double), typeof(ZoomControl), new PropertyMetadata(0.0)); + + public double RenderZoom + { + get { return (double)GetValue(RenderZoomProperty); } + set { SetValue(RenderZoomProperty, value); } + } + + public static readonly DependencyProperty RenderZoomProperty = + DependencyProperty.Register("RenderZoom", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsArrange, ZoomChangedHandler)); + + private static void ZoomChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs baseValue) + { + ZoomControl zc = (ZoomControl)d; + } + private static void TranslateChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs baseValue) + { + ZoomControl zc = (ZoomControl)d; + } + + #endregion + + private static readonly RoutedEvent ZoomChangedEvent = EventManager.RegisterRoutedEvent("ZoomChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ZoomControl)); + + public event RoutedEventHandler ZoomChanged + { + add { AddHandler(ZoomChangedEvent, value); } + remove { RemoveHandler(ZoomChangedEvent, value); } + } + + private void RaiseZoomChangedEvent() + { + var newEventArgs = new RoutedEventArgs(ZoomChangedEvent); + RaiseEvent(newEventArgs); + } + + static ZoomControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ZoomControl), new FrameworkPropertyMetadata(typeof(ZoomControl))); + } + + protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) + { + if (CheckMouseOverControlWheelHandle(_panPoint.HasValue)) + return; + + var point = e.GetPosition(this); + + + var oldValue = RenderZoom; + const double zoomPower = 1.25; + var newValue = RenderZoom * (e.Delta > 0 ? zoomPower : 1 / zoomPower); + if (UseAnimation) + { + DoubleAnimation anim = new DoubleAnimation(newValue, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.RenderZoomProperty, anim); + } + else + { + DoubleAnimation anim = new DoubleAnimation(newValue, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.RenderZoomProperty, anim); + } + + RaiseZoomChangedEvent(); + + var translateXTo = CoercePanTranslate(TranslateX, point.X, oldValue, newValue); + var translateYTo = CoercePanTranslate(TranslateY, point.Y, oldValue, newValue); + if (UseAnimation) + { + DoubleAnimation anim = new DoubleAnimation(translateXTo, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateXProperty, anim); + + anim = new DoubleAnimation(translateYTo, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateYProperty, anim); + } + else + { + DoubleAnimation anim = new DoubleAnimation(translateXTo, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateXProperty, anim); + + anim = new DoubleAnimation(translateYTo, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateYProperty, anim); + } + + e.Handled = true; + + base.OnPreviewMouseWheel(e); + } + public bool UseAnimation { get; set; } + private static bool CheckMouseOverControlWheelHandle(bool checkFlowDoc = false) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl)) return false; + var element = Mouse.DirectlyOver as DependencyObject; + if (element is ScrollViewer) return true; + + var scrollViewer = element.FindAncestor(); + if (scrollViewer != null) + { + return scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible + || scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible; + } + if (checkFlowDoc) + { + var flowDocument = element.FindAncestor(); + if (flowDocument != null) + { + return true; + } + } + + return false; + } + + private static double CoercePanTranslate(double oldTranslate, double mousePos, double oldZoom, double newZoom) + { + return Math.Round(oldTranslate + (oldTranslate - mousePos) * (newZoom - oldZoom) / oldZoom); + } + + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + + if (e.MiddleButton == MouseButtonState.Released) + { + _panPoint = null; + ReleaseMouseCapture(); + } + } + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + if (e.MiddleButton == MouseButtonState.Pressed && _panPoint.HasValue) + { + //PAN MODE + var vector = e.GetPosition(this) - _panPoint.Value; + _panPoint = _panPoint + vector; + CaptureMouse(); + TranslateX += vector.X; + TranslateY += vector.Y; + BeginAnimation(TranslateXProperty, null); + BeginAnimation(TranslateYProperty, null); + } + } + + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs b/BrightSharp.NET/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs new file mode 100644 index 0000000..02650ea --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs @@ -0,0 +1,168 @@ +using BrightSharp.Behaviors; +using System; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace BrightSharp.Extensions +{ + public static class MarkupExtensionProperties + { + public static CornerRadius GetCornerRadius(DependencyObject obj) + { + return (CornerRadius)obj.GetValue(CornerRadiusProperty); + } + public static void SetCornerRadius(DependencyObject obj, CornerRadius value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetHeader(DependencyObject obj) + { + return obj.GetValue(HeaderProperty); + } + public static void SetHeader(DependencyObject obj, object value) + { + obj.SetValue(HeaderProperty, value); + } + public static object GetLeadingElement(DependencyObject obj) + { + return obj.GetValue(CornerRadiusProperty); + } + public static void SetLeadingElement(DependencyObject obj, object value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetTrailingElement(DependencyObject obj) + { + return obj.GetValue(CornerRadiusProperty); + } + public static void SetTrailingElement(DependencyObject obj, object value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetIcon(DependencyObject obj) + { + return obj.GetValue(IconProperty); + } + public static void SetIcon(DependencyObject obj, object value) + { + obj.SetValue(IconProperty, value); + } + public static void SetHeaderHeight(DependencyObject obj, double value) + { + obj.SetValue(HeaderHeightProperty, value); + } + public static double GetHeaderHeight(DependencyObject obj) + { + return (double)obj.GetValue(HeaderHeightProperty); + } + + public static void SetHeaderVerticalAlignment(DependencyObject obj, VerticalAlignment value) + { + obj.SetValue(HeaderVerticalAlignmentProperty, value); + } + public static VerticalAlignment GetHeaderVerticalAlignment(DependencyObject obj) + { + return (VerticalAlignment)obj.GetValue(HeaderVerticalAlignmentProperty); + } + public static void SetHeaderHorizontalAlignment(DependencyObject obj, HorizontalAlignment value) + { + obj.SetValue(HeaderHorizontalAlignmentProperty, value); + } + public static HorizontalAlignment GetHeaderHorizontalAlignment(DependencyObject obj) + { + return (HorizontalAlignment)obj.GetValue(HeaderHorizontalAlignmentProperty); + } + public static void SetSpecialHeight(DependencyObject obj, double value) + { + obj.SetValue(SpecialHeightProperty, value); + } + public static double GetSpecialHeight(DependencyObject obj) + { + return (double)obj.GetValue(SpecialHeightProperty); + } + public static void SetSpecialWidth(DependencyObject obj, double value) + { + obj.SetValue(SpecialWidthProperty, value); + } + public static double GetSpecialWidth(DependencyObject obj) + { + return (double)obj.GetValue(SpecialWidthProperty); + } + public static Dock GetDocking(DependencyObject obj) + { + return (Dock)obj.GetValue(DockingProperty); + } + public static void SetDocking(DependencyObject obj, Dock value) + { + obj.SetValue(DockingProperty, value); + } + public static Thickness GetHeaderPadding(DependencyObject obj) + { + return (Thickness)obj.GetValue(HeaderPaddingProperty); + } + public static void SetHeaderPadding(DependencyObject obj, Thickness value) + { + obj.SetValue(HeaderPaddingProperty, value); + } + public static bool GetIsDragHelperVisible(DependencyObject obj) + { + return (bool)obj.GetValue(IsDragHelperVisibleProperty); + } + public static void SetIsDragHelperVisible(DependencyObject obj, bool value) + { + obj.SetValue(IsDragHelperVisibleProperty, value); + } + public static Brush GetSpecialBrush(DependencyObject obj) + { + return (Brush)obj.GetValue(SpecialBrushProperty); + } + public static void SetSpecialBrush(DependencyObject obj, Brush value) + { + obj.SetValue(SpecialBrushProperty, value); + } + + public static bool GetUseMinMaxSizeBehavior(Window obj) + { + return (bool)obj.GetValue(UseMinMaxSizeBehaviorProperty); + } + + public static void SetUseMinMaxSizeBehavior(Window obj, bool value) + { + obj.SetValue(UseMinMaxSizeBehaviorProperty, value); + } + + public static readonly DependencyProperty SpecialBrushProperty = DependencyProperty.RegisterAttached("SpecialBrush", typeof(Brush), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty IsDragHelperVisibleProperty = DependencyProperty.RegisterAttached("IsDragHelperVisible", typeof(bool), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(true)); + public static readonly DependencyProperty HeaderPaddingProperty = DependencyProperty.RegisterAttached("HeaderPadding", typeof(Thickness), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty LeadingElementProperty = DependencyProperty.RegisterAttached("LeadingElement", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty TrailingElementProperty = DependencyProperty.RegisterAttached("TrailingElement", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached("Header", typeof(object), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(null)); + public static readonly DependencyProperty DockingProperty = DependencyProperty.RegisterAttached("Docking", typeof(Dock), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderHeightProperty = DependencyProperty.RegisterAttached("HeaderHeight", typeof(double), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderVerticalAlignmentProperty = DependencyProperty.RegisterAttached("HeaderVerticalAlignment", typeof(VerticalAlignment), typeof(MarkupExtensionProperties), new PropertyMetadata(VerticalAlignment.Center)); + public static readonly DependencyProperty HeaderHorizontalAlignmentProperty = DependencyProperty.RegisterAttached("HeaderHorizontalAlignment", typeof(HorizontalAlignment), typeof(MarkupExtensionProperties), new PropertyMetadata(HorizontalAlignment.Left)); + public static readonly DependencyProperty SpecialHeightProperty = DependencyProperty.RegisterAttached("SpecialHeight", typeof(double), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); + public static readonly DependencyProperty SpecialWidthProperty = DependencyProperty.RegisterAttached("SpecialWidth", typeof(double), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); + public static readonly DependencyProperty UseMinMaxSizeBehaviorProperty = DependencyProperty.RegisterAttached("UseMinMaxSizeBehavior", typeof(bool), typeof(MarkupExtensionProperties), new PropertyMetadata(false, UseMinMaxSizeBehaviorChanged)); + + + private static void UseMinMaxSizeBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var window = d as Window; + if (window == null) return; + if ((bool)e.NewValue) + { + new MinMaxSize_Logic(window).OnAttached(); + } + else + { + // Not supported yet + } + } + } + +} diff --git a/BrightSharp.NET/BrightSharp.NET/Extensions/WpfExtensions.cs b/BrightSharp.NET/BrightSharp.NET/Extensions/WpfExtensions.cs new file mode 100644 index 0000000..9e0f579 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Extensions/WpfExtensions.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Media3D; + +namespace BrightSharp.Extensions +{ + public static class WpfExtensions + { + /// + /// Returns Parent item of DependencyObject + /// + /// Child object + /// Prefer LogicalTree when need. + /// Found item + public static DependencyObject GetParent(this DependencyObject obj, bool useLogicalTree = false) + { + if (!useLogicalTree && (obj is Visual || obj is Visual3D)) + return VisualTreeHelper.GetParent(obj) ?? LogicalTreeHelper.GetParent(obj); + else + return LogicalTreeHelper.GetParent(obj); + } + + public static IEnumerable GetAncestors(this DependencyObject obj, bool useLogicalTree = false) where T : DependencyObject + { + if (obj == null) yield break; + + var x = GetParent(obj, useLogicalTree); + + while (x != null && !(x is T)) + { + x = GetParent(x, useLogicalTree); + } + if (x != null) + yield return x as T; + else + yield break; + foreach (var item in GetAncestors(x, useLogicalTree)) + { + yield return item; + } + } + + public static T FindAncestor(this DependencyObject obj) where T : DependencyObject + { + return GetAncestors(obj).FirstOrDefault(); + } + + /// + /// Try find ItemsPanel of ItemsControl + /// + /// Where to search + /// Panel of ItemsControl + public static Panel GetItemsPanel(DependencyObject itemsControl) + { + if (itemsControl is Panel) return (Panel)itemsControl; + ItemsPresenter itemsPresenter = FindVisualChildren(itemsControl).FirstOrDefault(); + if (itemsPresenter == null) return null; + var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel; + return itemsPanel; + } + + /// + /// Check if object is valid (no errors found in logical children) + /// + /// Object to search + /// True if no errors found + public static bool IsValid(this DependencyObject obj) { + if (obj == null) return true; + if (Validation.GetHasError(obj)) return false; + foreach (var child in LogicalTreeHelper.GetChildren(obj).OfType()) { + if (child == null) continue; + if (child is UIElement ui) { + if (!ui.IsVisible || !ui.IsEnabled) continue; + } + if (!IsValid(child)) return false; + } + return true; + } + + /// + /// Search all textboxes to update invalid with UpdateSource(). For ex. when need update validation messages. + /// + /// Object where to search TextBoxes + public static void UpdateSources(this DependencyObject obj) { + if (obj == null) return; + if (Validation.GetHasError(obj)) { + //TODO Any types? + if (obj is TextBox tb) tb.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); + } + foreach (var item in FindLogicalChildren(obj)) { + UpdateSources(item); + } + } + + /// + /// Find all visual children of type T + /// + /// Type to search + /// Object where to search + /// Enumerator for items + public static IEnumerable FindVisualChildren(this DependencyObject depObj) where T : DependencyObject { + if (depObj != null && (depObj is Visual || depObj is Visual3D)) { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { + DependencyObject child = VisualTreeHelper.GetChild(depObj, i); + if (child != null && child is T) { + yield return (T)child; + } + + foreach (T childOfChild in FindVisualChildren(child)) { + yield return childOfChild; + } + } + } + } + + /// + /// Find all logical children of type T + /// + /// Type to search + /// Object where to search + /// Enumerator for items + public static IEnumerable FindLogicalChildren(this DependencyObject depObj) where T : DependencyObject { + if (depObj != null) { + foreach (object rawChild in LogicalTreeHelper.GetChildren(depObj)) { + if (rawChild is DependencyObject child) { + if (child is T) { + yield return (T)child; + } + + foreach (T childOfChild in FindLogicalChildren(child)) { + yield return childOfChild; + } + } + } + } + } + } + +} diff --git a/BrightSharp.NET/BrightSharp.NET/Interop/Constants.cs b/BrightSharp.NET/BrightSharp.NET/Interop/Constants.cs new file mode 100644 index 0000000..d18d5fe --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Interop/Constants.cs @@ -0,0 +1,11 @@ +namespace BrightSharp.Interop +{ + namespace Constants + { + internal enum MonitorFromWindowFlags + { + MONITOR_DEFAULTTONEAREST = 0x00000002 + } + + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Interop/NativeMethods.cs b/BrightSharp.NET/BrightSharp.NET/Interop/NativeMethods.cs new file mode 100644 index 0000000..2c75530 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Interop/NativeMethods.cs @@ -0,0 +1,20 @@ +using BrightSharp.Interop.Structures; +using System; +using System.Runtime.InteropServices; + +namespace BrightSharp.Interop +{ + internal static class NativeMethods + { + #region Monitor + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); + + #endregion + + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Interop/Structures.cs b/BrightSharp.NET/BrightSharp.NET/Interop/Structures.cs new file mode 100644 index 0000000..16a6ef2 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Interop/Structures.cs @@ -0,0 +1,130 @@ +using System; +using System.Runtime.InteropServices; + +namespace BrightSharp.Interop +{ + namespace Structures + { + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + + public RECT rcMonitor; + + public RECT rcWork; + + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal struct POINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal struct RECT + { + public int Left; + + public int Top; + + public int Right; + + public int Bottom; + + public static readonly RECT Empty; + + public int Width + { + get { + return Math.Abs(Right - Left); + } // Abs needed for BIDI OS + } + + public int Height + { + get { + return Bottom - Top; + } + } + + public RECT(int left, int top, int right, int bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + public RECT(RECT rcSrc) + { + Left = rcSrc.Left; + Top = rcSrc.Top; + Right = rcSrc.Right; + Bottom = rcSrc.Bottom; + } + + public bool IsEmpty + { + get { + // BUGBUG : On Bidi OS (hebrew arabic) left > right + return Left >= Right || Top >= Bottom; + } + } + + public override string ToString() + { + if (this == Empty) + { + return "RECT {Empty}"; + } + return "RECT { left : " + Left + " / top : " + Top + " / right : " + Right + " / bottom : " + + Bottom + " }"; + } + + public override bool Equals(object obj) + { + if (!(obj is RECT)) + { + return false; + } + return (this == (RECT)obj); + } + + public override int GetHashCode() + { + return Left.GetHashCode() + Top.GetHashCode() + Right.GetHashCode() + + Bottom.GetHashCode(); + } + + public static bool operator ==(RECT rect1, RECT rect2) + { + return (rect1.Left == rect2.Left && rect1.Top == rect2.Top && rect1.Right == rect2.Right && + rect1.Bottom == rect2.Bottom); + } + + public static bool operator !=(RECT rect1, RECT rect2) + { + return !(rect1 == rect2); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + public POINT ptReserved; + + public POINT ptMaxSize; + + public POINT ptMaxPosition; + + public POINT ptMinTrackSize; + + public POINT ptMaxTrackSize; + }; + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Properties/AssemblyInfo.cs b/BrightSharp.NET/BrightSharp.NET/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..107498e --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; + +[assembly: AssemblyDescription("")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, + ResourceDictionaryLocation.SourceAssembly +)] + +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/developer", "bs")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Extensions")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Behaviors")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Converters")] +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/diagrams", "bsDiag")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/diagrams", "BrightSharp.Diagrams")] diff --git a/BrightSharp.NET/BrightSharp.NET/Properties/Resources.Designer.cs b/BrightSharp.NET/BrightSharp.NET/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3b13e2c --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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 BrightSharp.Properties { + using System; + + + /// + /// 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", "16.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 (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BrightSharp.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/BrightSharp.NET/BrightSharp.NET/Properties/Resources.resx b/BrightSharp.NET/BrightSharp.NET/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/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/BrightSharp.NET/BrightSharp.NET/Properties/Settings.Designer.cs b/BrightSharp.NET/BrightSharp.NET/Properties/Settings.Designer.cs new file mode 100644 index 0000000..eca1af5 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/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 BrightSharp.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.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/BrightSharp.NET/BrightSharp.NET/Properties/Settings.settings b/BrightSharp.NET/BrightSharp.NET/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Controls/ZoomControl.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Controls/ZoomControl.xaml new file mode 100644 index 0000000..991346d --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Controls/ZoomControl.xaml @@ -0,0 +1,38 @@ + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml new file mode 100644 index 0000000..4028bcd --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml new file mode 100644 index 0000000..ae89737 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml @@ -0,0 +1,114 @@ + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml new file mode 100644 index 0000000..cdae020 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml @@ -0,0 +1,49 @@ + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Generic.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Generic.xaml new file mode 100644 index 0000000..63b9319 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Generic.xaml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Style.Blue.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Blue.xaml new file mode 100644 index 0000000..847e392 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Blue.xaml @@ -0,0 +1,326 @@ + + + False + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + + + #FF1B140F + #FFB6B6B6 + + + #FFFFF8B8 + + + Black + + + + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + #FFDADCEC + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Style.Classic.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Classic.xaml new file mode 100644 index 0000000..b299435 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Classic.xaml @@ -0,0 +1,283 @@ + + + + + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + Black + + + + + + + + + + + + + #E0E0EA + Black + #FAE0A0 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + #FFDADCEC + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Style.DarkBlue.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Style.DarkBlue.xaml new file mode 100644 index 0000000..ac18d2a --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Style.DarkBlue.xaml @@ -0,0 +1,307 @@ + + + True + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + + #99BDFF + #999999 + #FF2F596E + #FF10405B + #FF2B404B + + #FF414888 + #FF47909B + #D6D6D6 + #E6E6E6 + + #FF3333 + + #ffffff + + #555555 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + White + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Style.DevLab.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Style.DevLab.xaml new file mode 100644 index 0000000..4f6422d --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Style.DevLab.xaml @@ -0,0 +1,274 @@ + + + False + + 0 + 1 + + + 0 + 0 + 0 + 0 + 0,2,0,0 + + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + White + + + + + + Black + + + + + + + + + + + + + + + + + + + + Black + + + + + + + + #E3E3E3 + #FFD6E6E6 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + + #FFEEEEEE + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Style.Silver.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Silver.xaml new file mode 100644 index 0000000..a0e1f31 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Style.Silver.xaml @@ -0,0 +1,324 @@ + + + False + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + + + + + Black + + + + + + + + + + + + + + + + + + + + + + + + + + + + Black + + + + + + #DEDEDE + #FFB6B6B6 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + + #FFCED0E1 + #FF47909B + + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.cs b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.cs new file mode 100644 index 0000000..574476a --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.cs @@ -0,0 +1,41 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Themes +{ + + internal partial class ThemeStatic + { + public void CalendarPreviewMouseUp(object sender, MouseEventArgs e) { + if (Mouse.Captured is CalendarItem) { Mouse.Capture(null); } + } + public void DatePickerUnloaded(object sender, RoutedEventArgs e) { + if (sender == null) return; + DependencyObject child = ((Popup)((DatePicker)sender).Template.FindName("PART_Popup", (FrameworkElement)sender))?.Child; + while (child != null && !(child is AdornerDecorator)) + child = VisualTreeHelper.GetParent(child) ?? LogicalTreeHelper.GetParent(child); + if (((AdornerDecorator)child)?.Child is Calendar) ((AdornerDecorator)child).Child = null; + } + + + private void closeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.Close(); + } + + private void maximizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = window.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; + } + + private void minimizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = WindowState.Minimized; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.xaml new file mode 100644 index 0000000..c7eb0bd --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.Static.xaml @@ -0,0 +1,5729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Theme.cs b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.cs new file mode 100644 index 0000000..219a1a3 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.cs @@ -0,0 +1,40 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Themes +{ + + internal partial class Theme + { + public void CalendarPreviewMouseUp(object sender, MouseEventArgs e) { + if (Mouse.Captured is CalendarItem) { Mouse.Capture(null); } + } + public void DatePickerUnloaded(object sender, RoutedEventArgs e) { + if (sender == null) return; + DependencyObject child = ((Popup)((DatePicker)sender).Template.FindName("PART_Popup", (FrameworkElement)sender))?.Child; + while (child != null && !(child is AdornerDecorator)) + child = VisualTreeHelper.GetParent(child) ?? LogicalTreeHelper.GetParent(child); + if (((AdornerDecorator)child)?.Child is Calendar) ((AdornerDecorator)child).Child = null; + } + + + private void closeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.Close(); + } + + private void maximizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = window.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; + } + + private void minimizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = WindowState.Minimized; + } + } +} diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/Theme.xaml b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.xaml new file mode 100644 index 0000000..d32d396 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/Theme.xaml @@ -0,0 +1,5760 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/ThemeManager.cs b/BrightSharp.NET/BrightSharp.NET/Themes/ThemeManager.cs new file mode 100644 index 0000000..0df032b --- /dev/null +++ b/BrightSharp.NET/BrightSharp.NET/Themes/ThemeManager.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; + +namespace BrightSharp.Themes +{ + public enum ColorThemes + { + Classic, + DevLab, + Silver, + Blue, + DarkBlue + } + + public static class ThemeManager + { + private const string StyleDictionaryPattern = @"(?<=.+style\.)(.*?)(?=\.xaml)"; + private const string ThemeDictionaryUri = "/brightsharp;component/themes/theme.xaml"; + + private static ColorThemes? ThemeField; + + public static ColorThemes? Theme + { + get { + if (ThemeField.HasValue) return ThemeField.Value; + var curStyleRes = Resources.Where(r => r.Source != null && + Regex.IsMatch(r.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase)).FirstOrDefault(); + if (curStyleRes == null) return null; + var match = Regex.Match(curStyleRes.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase); + ThemeField = (ColorThemes)Enum.Parse(typeof(ColorThemes), match.Value, true); + return ThemeField.Value; + } + set { + _ = SetTheme(value); + } + } + + public static async Task SetTheme(ColorThemes? value, DispatcherPriority priority = DispatcherPriority.Background) + { + if (ThemeField == value) { return; } + ThemeField = value; + await Application.Current.Dispatcher.InvokeAsync(() => + { + if (ThemeField != value) return; + Application.Current.Resources.BeginInit(); + + var curStyleRes = Resources.Where(r => r.Source != null && + Regex.IsMatch(r.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase)).FirstOrDefault(); + var curThemeRes = Resources.Where(r => r.Source != null && r.Source.OriginalString.Equals(ThemeDictionaryUri, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (curThemeRes != null) + Resources.Remove(curThemeRes); + if (curStyleRes != null) + Resources.Remove(curStyleRes); + if (value == null) return; + Resources.Add(new ResourceDictionary() { Source = new Uri($"/brightsharp;component/themes/style.{value}.xaml", UriKind.RelativeOrAbsolute) }); + Resources.Add(new ResourceDictionary() { Source = new Uri(ThemeDictionaryUri, UriKind.RelativeOrAbsolute) }); + + Application.Current.Resources.EndInit(); + ThemeChanged?.Invoke(null, EventArgs.Empty); + }, priority); + } + + public static event EventHandler ThemeChanged; + + private static ICollection Resources + { + get { return Application.Current.Resources.MergedDictionaries; } + } + } + +} diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/icons/app.png b/BrightSharp.NET/BrightSharp.NET/Themes/icons/app.png new file mode 100644 index 0000000000000000000000000000000000000000..9d372aab5d774bce956282d581c83c98fdd4782f GIT binary patch literal 367 zcmV-#0g(QQP)7g! zKzG@A0hc1KJ&B8)#icv1;tdRB5!ZqQ@?+G2IO#vDdWf!jQt+l=nD2GHqDRFTaY)h4 z)8dxuU}F^4WUwwZR)q$(el(hW zKn&{7Wm9by42O{9z5nZb@dL;FZpi(-`>uL<`>Kh`5|4K$z4CK>kasSfmb*-)6ogF% z`;l`>Yuy<*YyWd*lraXvCIiP#qMVY*oxyIGPR})v9SBRdZIgjzx7-~FOSb0(L2urK!^W@@w-s>X8hZd!RBC_pIuG6o!jG4^&*E+0c2tVTm^g5x*}*Pr6fbER}%cyG7EAl%n#kj-Y{ zv{<};Z8je^5l9tGq(PD)AUw+DG|7!=0$MatiAihBw`QTWE4}gAvb5Z8*HKRQQ;&ne zaLLMJy}r>J52OewKo|m~Az}72gRfpshhJ9(ADzxRYcC;zloEsxI%pmQL@Y+F5eX7s zhC8H?vA1O)*=RI|lR`lU!9!)?DayPNxY1ZxoA##q*I_23|4V8bLLy=KO%%mq&99Nv zjpkv)EnOq$e7gc9(iV|H@#Q2Ea}2PWN%9j_K$Ul0SC0p&G*BYWDai@}HpJOowVMB( z&s|*@Jk{^_$G4S=eO@ZTWHNzNGKC6>fQ4^m)#4t;ZX|Y4mD&ai_XM{v{%@NN8@9bq tMN?~vORp7e4Oz_9=c%?35BE=i0RT5r8CncW4OIXD002ovPDHLkV1gUd&$j>o literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/icons/cut.png b/BrightSharp.NET/BrightSharp.NET/Themes/icons/cut.png new file mode 100644 index 0000000000000000000000000000000000000000..9a0ae031ac67c861211043bb9f0c9f51b779e02a GIT binary patch literal 510 zcmV8k}5^aE-thCOJo3~!W_`iSuX885< zHv`cI96WGnp0J>x$d#+tAA|TmfBt0P=HVu200UAWN-tfp>h0^-um4}XcgC743F;|t9!tqU}4dE=0Eel-_IHT z{{G1L?~lfjCMQOmUNG;xtY+4J;lF9qNsyp0$Teo=+xA-3?FU7%wn5_LZoA5Dk8!3% zroVr7eY(20i2d((5ce&}HK#hg(ir~!`ej?atL4J{+-}A{zl1T;0Sqwy`z3#4N%4Hf zKR=O$?;dM)_xStmJ)?d3hL?Z7zdwP~3pNc0!5sVYP1s^U5r~a}SQ(}dBM=#X{{U*< z@c+}pORd-f7m5+;u|%UWlzs@rZ}6o95C8};0RM>OFInyic>n+a07*qoM6N<$f-eU9 A(*OVf literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/icons/paste.png b/BrightSharp.NET/BrightSharp.NET/Themes/icons/paste.png new file mode 100644 index 0000000000000000000000000000000000000000..ee4bd3e94db2a21985dcdf4c54a90b5583f45bd6 GIT binary patch literal 715 zcmV;+0yO=JP)Q562}d-uh5XdBbk zO^X!4Av#qgigc=`RY*WrH#do+T_l4@3r^a(E`m;0(m_Oo#^NG%@P|~FB9@4Q_(Kw3 zUi04l@!b0!FY1s3H@WYgbH4MP?;Q5v#sU}=Tpgk@d>$<7XlMm62ihB9`QQm8%Rs|{ zc~?;vxw)J4AJ}iMl&onbN=io%BEp%I1!!_G0(iOgMo09f7^82#&LGQ>k@XXzH7=s4 zbn$WpOoeD}{6ubI5(EmzaWFbEigNiX0eEqGn*G32hh&Y>B?po2&P0;X3NjQadBd=!^1%wdo{ zuGLE1FbVw*LP1gSHJ$9Z(A$$|2#BAkZC2k3;)1 zxVO5BeEwLPTsVEo`b-2jzk7b0a$@wDff*ySK_2%|sa&&n<2O|WF^mz+c8~^v-y#hZ zA{t*r)k7iDK0VLF%F11AzNmw9j(UBA-gxTgre@G>Q&CdZ&^Fs9RT|)O7uOdTQwGKP zd15R30JeorD|t)+h+@)#Ww5-ogcCC}P*lLgohugm07eMEO8`2N#RL%>FF|l=-qmU~ zO)wh7TA9Hx@ZVjr+5GfvHrA9`24c_0Vb_UQ)p7ory%E>7V~u^L%ru?s|4UMP`uv&d xb;qUZkMu7TIOaG`hYeV?<3<7uHu*<@0RVmFQ(}77sv-aY002ovPDHLkV1i5dKS2Nh literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/BrightSharp.NET/Themes/icons/undo.png b/BrightSharp.NET/BrightSharp.NET/Themes/icons/undo.png new file mode 100644 index 0000000000000000000000000000000000000000..0c196ec096e723d2074006e40215e54a4046817d GIT binary patch literal 1307 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHn2V^ecO3kx$t14lzcLsw%*0~d2Q0~b>Z zXA3uDGe=99UYGpj(%jU%5}4i;gkE!;dO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPrc z(>$o&6x?nx#i>^x=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6dgn2wNCpPReoq(2 zkcwMxf_*hy0!99vtIanu{^a9)%Kzqx2m?)N?MXb+sfQyXPH;&_Mrc^8Zu8nEW~R(- zZ6DaRY0|`-6aGB0?=igG^Wom^b6@vQn9|xC9RIxJT={;#`+KJ^nexMzAzInp-`{#zZ4i^^R01xF?53F3**WOLrrutMR{c?fjt?WOn8YjOW zn7M54{IDkxpBQKV4nMf{ZTEuAsK-q%+h@I6mb!T5sq5Q>ES=L2v~Rv$y+%%@plE8t zp8d^Fb_NBctbgc~9cno3kbCTN^OHIEmbh-uk>*XU{P48OKzQe|!asuL7qe}SJU)5k z<++SE2Af<}TBdB98yWG6|NYc2Pb%){P0L9;TNS%@hji_cCvGBqzRfdtxV(B)QJK1A z>vVVZo+s+(#Uz8T{#}^3{2_0F?Q(8MgG;d|zNKkR7Wk5$s8b@x&7<4$^6bif4@14@ zzh7Hrvn^AX$y+=ri#`4EHW#+Nk^kOoW8l7Ae*L(T>l`DIm2(!>9*q2d(t5%F{SE4j aYz*y^( + + + \ No newline at end of file diff --git a/BrightSharp.NET/BrightSharp.csproj b/BrightSharp.NET/BrightSharp.csproj new file mode 100644 index 0000000..a38c6d0 --- /dev/null +++ b/BrightSharp.NET/BrightSharp.csproj @@ -0,0 +1,74 @@ + + + + net5.0-windows + true + AnyCPU;x64 + + + + + + + + + + + + + + + + + + + + + + + + + Code + + + Theme.xaml + + + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + diff --git a/BrightSharp.NET/Commands/AsyncCommand.cs b/BrightSharp.NET/Commands/AsyncCommand.cs new file mode 100644 index 0000000..400cab1 --- /dev/null +++ b/BrightSharp.NET/Commands/AsyncCommand.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading.Tasks; +using System.Windows.Input; + +namespace BrightSharp.Commands +{ + public class AsyncCommand : ICommand + { + private readonly Func _execute; + private readonly Func _canExecute; + private Action _onComplete; + private Action _onFail; + private bool _isExecuting; + + public AsyncCommand(Func execute) : this(p => execute?.Invoke()) + { + } + + public AsyncCommand(Func execute) : this(execute, o => true) + { + } + + public AsyncCommand(Func execute, Func canExecute) + { + _execute = execute; + _canExecute = canExecute; + } + + public AsyncCommand OnComplete(Action onComplete) + { + _onComplete = onComplete; + return this; + } + public AsyncCommand OnFail(Action onFail) + { + _onFail = onFail; + return this; + } + + public bool CanExecute(object parameter) + { + return !_isExecuting && _canExecute(parameter); + } + + public event EventHandler CanExecuteChanged; + + public async void Execute(object parameter) + { + _isExecuting = true; + OnCanExecuteChanged(); + try + { + await _execute(parameter); + _onComplete?.Invoke(); + } + catch (Exception ex) + { + while (ex.InnerException != null) + ex = ex.InnerException; + _onFail?.Invoke(ex); + } + finally + { + _isExecuting = false; + OnCanExecuteChanged(); + } + } + + public virtual void OnCanExecuteChanged() + { + CanExecuteChanged?.Invoke(this, new EventArgs()); + } + } +} diff --git a/BrightSharp.NET/Commands/RelayCommand.cs b/BrightSharp.NET/Commands/RelayCommand.cs new file mode 100644 index 0000000..1c13498 --- /dev/null +++ b/BrightSharp.NET/Commands/RelayCommand.cs @@ -0,0 +1,71 @@ +using System; +using System.Windows.Input; + +namespace BrightSharp.Commands +{ + public class RelayCommand : ICommand + { + private readonly Action _methodToExecute; + private readonly Action _methodToExecuteWithParam; + private readonly Func _canExecuteEvaluator; + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public RelayCommand(Action methodToExecute, Func canExecuteEvaluator = null) + { + _methodToExecuteWithParam = methodToExecute; + _canExecuteEvaluator = canExecuteEvaluator; + } + + public RelayCommand(Action methodToExecute) + { + _methodToExecute = methodToExecute; + } + + public bool CanExecute(object parameter) + { + if (_canExecuteEvaluator == null) + return true; + else + return _canExecuteEvaluator.Invoke(parameter); + } + public void Execute(object parameter) + { + _methodToExecuteWithParam?.Invoke(parameter); + _methodToExecute?.Invoke(); + } + } + + public class RelayCommand : ICommand where T : class + { + private readonly Action _methodToExecuteWithParam; + private readonly Func _canExecuteEvaluator; + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public RelayCommand(Action methodToExecute, Func canExecuteEvaluator = null) + { + _methodToExecuteWithParam = methodToExecute; + _canExecuteEvaluator = canExecuteEvaluator; + } + + public bool CanExecute(object parameter) + { + if (_canExecuteEvaluator == null) + return true; + return _canExecuteEvaluator.Invoke(parameter as T); + } + public void Execute(object parameter) + { + _methodToExecuteWithParam?.Invoke(parameter as T); + } + } +} diff --git a/BrightSharp.NET/Converters/IntToValueConverter.cs b/BrightSharp.NET/Converters/IntToValueConverter.cs new file mode 100644 index 0000000..514a350 --- /dev/null +++ b/BrightSharp.NET/Converters/IntToValueConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections; +using System.Globalization; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + public class IntToValueConverter : IValueConverter + { + public ulong? TrueValueInt { get; set; } = null; + public ulong? FalseValueInt { get; set; } = 0; + + + public object TrueValue { get; set; } = true; + public object FalseValue { get; set; } = false; + + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + { + value = false; + } + if (value is string valueStr) + { + value = valueStr.Length > 0; + } + if (value is bool valueBool) + { + value = valueBool ? 1 : 0; + } + if (value is ICollection valueCol) + { + value = valueCol.Count; + } + if (value is Enum en) + { + value = System.Convert.ToInt32(en); + } + if (ulong.TryParse(value.ToString(), out ulong valueLong)) + { + // Exact match for false + if (FalseValueInt.HasValue && FalseValueInt == valueLong) return FalseValue; + // Exact match for true + if (TrueValueInt.HasValue && TrueValueInt == valueLong) return TrueValue; + // Any value for false + if (!FalseValueInt.HasValue) return FalseValue; + // Any value for true + if (!TrueValueInt.HasValue) return TrueValue; + } + return TrueValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + // Convert with potential lose exact value match + return Equals(value, TrueValue) ? TrueValueInt : FalseValueInt; + } + } +} diff --git a/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs b/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs new file mode 100644 index 0000000..9f4bcfc --- /dev/null +++ b/BrightSharp.NET/Converters/InverseBooleanToVisibilityConverter.cs @@ -0,0 +1,23 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + [Localizability(LocalizationCategory.NeverLocalize)] + public class InverseBooleanToVisibilityConverter : IValueConverter + { + private BooleanToVisibilityConverter _converter = new BooleanToVisibilityConverter(); + + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { + var result = _converter.Convert(value, targetType, parameter, culture) as Visibility?; + return result == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { + var result = _converter.ConvertBack(value, targetType, parameter, culture) as bool?; + return result == true ? false : true; + } + } +} diff --git a/BrightSharp.NET/Converters/ThicknessConverter.cs b/BrightSharp.NET/Converters/ThicknessConverter.cs new file mode 100644 index 0000000..198b7c5 --- /dev/null +++ b/BrightSharp.NET/Converters/ThicknessConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace BrightSharp.Converters +{ + internal class ThicknessConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is Thickness) + { + var offset = double.Parse(parameter.ToString(), CultureInfo.InvariantCulture.NumberFormat); + var thick = (Thickness)value; + + return new Thickness(Math.Max(0, thick.Left + offset), + Math.Max(0, thick.Top + offset), + Math.Max(0, thick.Right + offset), + Math.Max(0, thick.Bottom + offset)); + } + else if(value is CornerRadius) + { + var offset = double.Parse(parameter.ToString(), CultureInfo.InvariantCulture.NumberFormat); + var thick = (CornerRadius)value; + + return new CornerRadius(Math.Max(0, thick.TopLeft + offset), + Math.Max(0, thick.TopRight + offset), + Math.Max(0, thick.BottomRight + offset), + Math.Max(0, thick.BottomLeft + offset)); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs b/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs new file mode 100644 index 0000000..343b2d6 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Adorners/ResizeRotateAdorner.cs @@ -0,0 +1,48 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeRotateAdorner : Adorner + { + private VisualCollection visuals; + private ResizeRotateChrome chrome; + + protected override int VisualChildrenCount + { + get + { + return visuals.Count; + } + } + + public ResizeRotateAdorner(ContentControl designerItem) + : base(designerItem) + { + SnapsToDevicePixels = true; + chrome = new ResizeRotateChrome(); + chrome.DataContext = designerItem; + visuals = new VisualCollection(this); + visuals.Add(chrome); + Focusable = true; + } + + + + protected override Size ArrangeOverride(Size arrangeBounds) + { + chrome.Arrange(new Rect(arrangeBounds)); + return arrangeBounds; + } + + protected override Visual GetVisualChild(int index) + { + return visuals[index]; + } + + } +} diff --git a/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs b/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs new file mode 100644 index 0000000..7f60b09 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Adorners/ResizeRotateChrome.cs @@ -0,0 +1,15 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeRotateChrome : Control + { + static ResizeRotateChrome() + { + FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(ResizeRotateChrome), new FrameworkPropertyMetadata(typeof(ResizeRotateChrome))); + } + } +} diff --git a/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs b/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs new file mode 100644 index 0000000..9c68a88 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Adorners/SizeAdorner.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class SizeAdorner : Adorner + { + private SizeChrome chrome; + private VisualCollection visuals; + private FrameworkElement designerItem; + + protected override int VisualChildrenCount + { + get + { + return visuals.Count; + } + } + + public SizeAdorner(FrameworkElement designerItem) + : base(designerItem) + { + SnapsToDevicePixels = true; + this.designerItem = designerItem; + chrome = new SizeChrome(); + chrome.DataContext = designerItem; + visuals = new VisualCollection(this); + visuals.Add(chrome); + } + + protected override Visual GetVisualChild(int index) + { + return visuals[index]; + } + + protected override Size ArrangeOverride(Size arrangeBounds) + { + chrome.Arrange(new Rect(new Point(0.0, 0.0), arrangeBounds)); + return arrangeBounds; + } + } +} diff --git a/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs b/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs new file mode 100644 index 0000000..1160a92 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Adorners/SizeChrome.cs @@ -0,0 +1,34 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace BrightSharp.Diagrams +{ + + [ToolboxItem(false)] + public class SizeChrome : Control + { + static SizeChrome() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SizeChrome), new FrameworkPropertyMetadata(typeof(SizeChrome))); + } + } + + public class DoubleFormatConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + double d = (double)value; + if (double.IsNaN(d)) return "(Auto)"; + return Math.Round(d); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} diff --git a/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs b/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs new file mode 100644 index 0000000..918d9b4 --- /dev/null +++ b/BrightSharp.NET/Diagrams/DesignerItemDecorator.cs @@ -0,0 +1,103 @@ +using System; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.ComponentModel; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class DesignerItemDecorator : Control + { + private Adorner adorner; + + public bool ShowDecorator + { + get { return (bool)GetValue(ShowDecoratorProperty); } + set { SetValue(ShowDecoratorProperty, value); } + } + + public static readonly DependencyProperty ShowDecoratorProperty = + DependencyProperty.Register("ShowDecorator", typeof(bool), typeof(DesignerItemDecorator), + new FrameworkPropertyMetadata(false, new PropertyChangedCallback(ShowDecoratorProperty_Changed))); + + public DesignerItemDecorator() + { + Unloaded += new RoutedEventHandler(DesignerItemDecorator_Unloaded); + } + + private void HideAdorner() + { + if (adorner != null) + { + adorner.Visibility = Visibility.Hidden; + } + } + + private void ShowAdorner() + { + if (adorner == null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); + + if (adornerLayer != null) + { + ContentControl designerItem = DataContext as ContentControl; + Canvas canvas = VisualTreeHelper.GetParent(designerItem) as Canvas; + adorner = new ResizeRotateAdorner(designerItem); + adornerLayer.Add(adorner); + + if (ShowDecorator) + { + adorner.Visibility = Visibility.Visible; + + var anim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(.2)); + adorner.BeginAnimation(OpacityProperty, anim); + } + else + { + adorner.Visibility = Visibility.Hidden; + } + } + } + else + { + adorner.Visibility = Visibility.Visible; + + var anim = new DoubleAnimation(0, 1, TimeSpan.FromSeconds(.2)); + adorner.BeginAnimation(OpacityProperty, anim); + } + } + + private void DesignerItemDecorator_Unloaded(object sender, RoutedEventArgs e) + { + if (adorner != null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this); + if (adornerLayer != null) + { + adornerLayer.Remove(adorner); + } + + adorner = null; + } + } + + private static void ShowDecoratorProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + DesignerItemDecorator decorator = (DesignerItemDecorator)d; + bool showDecorator = (bool)e.NewValue; + + if (showDecorator) + { + decorator.ShowAdorner(); + } + else + { + decorator.HideAdorner(); + } + } + } +} diff --git a/BrightSharp.NET/Diagrams/SelectionBehavior.cs b/BrightSharp.NET/Diagrams/SelectionBehavior.cs new file mode 100644 index 0000000..a1ed199 --- /dev/null +++ b/BrightSharp.NET/Diagrams/SelectionBehavior.cs @@ -0,0 +1,96 @@ +using BrightSharp.Extensions; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace BrightSharp.Diagrams +{ + public static class SelectionBehavior + { + public static void Attach(FrameworkElement fe) + { + FrameworkElement selectedControl = null; + Style designerStyle = (Style)Application.Current.FindResource("DesignerItemStyle"); + if (fe is Panel) + { + var fePanel = (Panel)fe; + fe.PreviewMouseLeftButtonDown += (s, e) => + { + if (e.Source is DependencyObject) + { + var clickedElement = ((DependencyObject)e.OriginalSource).GetAncestors().FirstOrDefault(el => el.Style == designerStyle && WpfExtensions.GetItemsPanel(el.GetParent(true)) == fe); + if (clickedElement == null) + { + foreach (DependencyObject item in fePanel.Children) + { + Selector.SetIsSelected(item, false); + } + selectedControl = null; + return; + } + foreach (var control in fePanel.Children.OfType()) + { + if (ProcessControl(control, clickedElement, ref selectedControl)) + { + if (selectedControl is ContentControl cc && cc.Content is ButtonBase) + { + e.Handled = true; + return; + } + } + } + + } + }; + } + else if (fe is ItemsControl) + { + var feItemsControl = (ItemsControl)fe; + fe.PreviewMouseLeftButtonDown += (s, e) => + { + if (e.Source is DependencyObject) + { + var clickedElement = ((DependencyObject)e.Source).GetAncestors().FirstOrDefault(el => el.Style == designerStyle && el.Parent == fe); + if (clickedElement == null) + { + foreach (DependencyObject item in feItemsControl.Items) + { + Selector.SetIsSelected(item, false); + } + selectedControl = null; + return; + } + foreach (var control in feItemsControl.Items.OfType()) + { + if (ProcessControl(control, clickedElement, ref selectedControl)) + { + if (selectedControl is ContentControl cc && cc.Content is ButtonBase) + { + e.Handled = true; + return; + } + } + } + + } + }; + } + } + + private static bool ProcessControl(FrameworkElement control, FrameworkElement clickedElement, ref FrameworkElement selectedControl) + { + if (control == clickedElement && control != selectedControl) + { + if (selectedControl != null) + { + Selector.SetIsSelected(selectedControl, false); + } + Selector.SetIsSelected(control, true); + selectedControl = control; + return true; + } + return false; + } + } +} diff --git a/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs b/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs new file mode 100644 index 0000000..e935e94 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Thumbs/MoveThumb.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class MoveThumb : Thumb + { + private RotateTransform rotateTransform; + private FrameworkElement designerItem; + private static int? zIndex = null; + + public MoveThumb() + { + DragStarted += MoveThumb_DragStarted; + DragDelta += MoveThumb_DragDelta; + DragCompleted += MoveThumb_DragCompleted; + } + + private void MoveThumb_DragCompleted(object sender, DragCompletedEventArgs e) + { + //TODO Need think about ZIndex changes + } + + private void MoveThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as FrameworkElement; + + if (designerItem != null) + { + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (designerItem.GetBindingExpression(Panel.ZIndexProperty) == null) + { + zIndex = Math.Max(zIndex ?? 0, Panel.GetZIndex(designerItem)); + Panel.SetZIndex(designerItem, zIndex.Value + 1); + } + } + } + + private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null) + { + Point dragDelta = new Point(e.HorizontalChange, e.VerticalChange); + + double gridSize = 0; + + var zoomControl = designerItem.Parent as ZoomControl; + if (zoomControl != null) gridSize = zoomControl.GridSize; + + if (rotateTransform != null) + { + dragDelta = rotateTransform.Transform(dragDelta); + } + if (double.IsNaN(Canvas.GetLeft(designerItem))) Canvas.SetLeft(designerItem, 0); + if (double.IsNaN(Canvas.GetTop(designerItem))) Canvas.SetTop(designerItem, 0); + + var newLeft = Canvas.GetLeft(designerItem) + dragDelta.X; + var newTop = Canvas.GetTop(designerItem) + dragDelta.Y; + if (gridSize > 0) + { + newLeft = Math.Truncate(newLeft / gridSize) * gridSize; + newTop = Math.Truncate(newTop / gridSize) * gridSize; + } + Canvas.SetLeft(designerItem, newLeft); + Canvas.SetTop(designerItem, newTop); + + } + } + } +} diff --git a/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs b/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs new file mode 100644 index 0000000..4db4666 --- /dev/null +++ b/BrightSharp.NET/Diagrams/Thumbs/ResizeThumb.cs @@ -0,0 +1,160 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Media; +using System.Windows.Input; +using System.ComponentModel; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class ResizeThumb : Thumb + { + private RotateTransform rotateTransform; + private double angle; + private Adorner adorner; + private Point transformOrigin; + private FrameworkElement designerItem; + private FrameworkElement canvas; + + public ResizeThumb() + { + DragStarted += new DragStartedEventHandler(ResizeThumb_DragStarted); + DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta); + DragCompleted += new DragCompletedEventHandler(ResizeThumb_DragCompleted); + MouseRightButtonDown += new MouseButtonEventHandler(ResizeThumb_MouseRightButtonDown); + } + + private void ResizeThumb_MouseRightButtonDown(object sender, MouseButtonEventArgs e) + { + designerItem = designerItem ?? DataContext as FrameworkElement; + + if (VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom) + { + designerItem.Height = double.NaN; + } + if (HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right) + { + designerItem.Width = double.NaN; + } + } + + private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as ContentControl; + + if (designerItem != null) + { + canvas = VisualTreeHelper.GetParent(designerItem) as FrameworkElement; + + if (canvas != null) + { + transformOrigin = designerItem.RenderTransformOrigin; + + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform != null) + { + angle = rotateTransform.Angle * Math.PI / 180.0; + } + else + { + angle = 0.0d; + } + + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas); + if (adornerLayer != null) + { + adorner = new SizeAdorner(designerItem); + adornerLayer.Add(adorner); + } + } + } + } + + private void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null) + { + double deltaVertical, deltaHorizontal; + if (double.IsNaN(Canvas.GetTop(designerItem))) Canvas.SetTop(designerItem, 0); + if (double.IsNaN(Canvas.GetLeft(designerItem))) Canvas.SetLeft(designerItem, 0); + if ((VerticalAlignment == VerticalAlignment.Top || VerticalAlignment == VerticalAlignment.Bottom) && double.IsNaN(designerItem.Height)) designerItem.Height = designerItem.ActualHeight; + if ((HorizontalAlignment == HorizontalAlignment.Left || HorizontalAlignment == HorizontalAlignment.Right) && double.IsNaN(designerItem.Width)) designerItem.Width = designerItem.ActualWidth; + + var zoomControl = designerItem.Parent as dynamic; + double.TryParse(zoomControl.Tag as string, out var gridSize); + + var verticalChange = e.VerticalChange; + var horizontalChange = e.HorizontalChange; + + if (gridSize > 0) + { + verticalChange = Math.Truncate(verticalChange / gridSize) * gridSize; + horizontalChange = Math.Truncate(horizontalChange / gridSize) * gridSize; + } + if (verticalChange != 0) + { + switch (VerticalAlignment) + { + case System.Windows.VerticalAlignment.Bottom: + deltaVertical = Math.Min(-verticalChange, designerItem.ActualHeight - designerItem.MinHeight); + deltaVertical = Math.Max(deltaVertical, designerItem.ActualHeight - designerItem.MaxHeight); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle)))); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) - deltaVertical * transformOrigin.Y * Math.Sin(-angle)); + designerItem.Height -= deltaVertical; + break; + case System.Windows.VerticalAlignment.Top: + deltaVertical = Math.Min(verticalChange, designerItem.ActualHeight - designerItem.MinHeight); + deltaVertical = Math.Max(deltaVertical, designerItem.ActualHeight - designerItem.MaxHeight); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaVertical * Math.Cos(-angle) + (transformOrigin.Y * deltaVertical * (1 - Math.Cos(-angle)))); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaVertical * Math.Sin(-angle) - (transformOrigin.Y * deltaVertical * Math.Sin(-angle))); + designerItem.Height -= deltaVertical; + break; + default: + break; + } + } + if (horizontalChange != 0) + { + switch (HorizontalAlignment) + { + case System.Windows.HorizontalAlignment.Left: + deltaHorizontal = Math.Min(horizontalChange, designerItem.ActualWidth - designerItem.MinWidth); + deltaHorizontal = Math.Max(deltaHorizontal, designerItem.ActualWidth - designerItem.MaxWidth); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) + deltaHorizontal * Math.Sin(angle) - transformOrigin.X * deltaHorizontal * Math.Sin(angle)); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + deltaHorizontal * Math.Cos(angle) + (transformOrigin.X * deltaHorizontal * (1 - Math.Cos(angle)))); + designerItem.Width -= deltaHorizontal; + break; + case System.Windows.HorizontalAlignment.Right: + deltaHorizontal = Math.Min(-horizontalChange, designerItem.ActualWidth - designerItem.MinWidth); + deltaHorizontal = Math.Max(deltaHorizontal, designerItem.ActualWidth - designerItem.MaxWidth); + Canvas.SetTop(designerItem, Canvas.GetTop(designerItem) - transformOrigin.X * deltaHorizontal * Math.Sin(angle)); + Canvas.SetLeft(designerItem, Canvas.GetLeft(designerItem) + (deltaHorizontal * transformOrigin.X * (1 - Math.Cos(angle)))); + designerItem.Width -= deltaHorizontal; + break; + default: + break; + } + } + } + + e.Handled = true; + } + + private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e) + { + if (adorner != null) + { + AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(canvas); + if (adornerLayer != null) + { + adornerLayer.Remove(adorner); + } + + adorner = null; + } + } + } +} diff --git a/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs b/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs new file mode 100644 index 0000000..1edb7ac --- /dev/null +++ b/BrightSharp.NET/Diagrams/Thumbs/RotateThumb.cs @@ -0,0 +1,88 @@ +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Diagrams +{ + [ToolboxItem(false)] + public class RotateThumb : Thumb + { + private double initialAngle; + private RotateTransform rotateTransform; + private Vector startVector; + private Point centerPoint; + private ContentControl designerItem; + private Canvas canvas; + + public RotateThumb() + { + DragDelta += new DragDeltaEventHandler(RotateThumb_DragDelta); + DragStarted += new DragStartedEventHandler(RotateThumb_DragStarted); + MouseRightButtonDown += RotateThumb_MouseLeftButtonDown; + } + + private void RotateThumb_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (e.RightButton == MouseButtonState.Pressed) + { + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform != null) + { + rotateTransform.Angle = 0; + designerItem.InvalidateMeasure(); + } + } + } + + private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e) + { + designerItem = DataContext as ContentControl; + + if (designerItem != null) + { + canvas = VisualTreeHelper.GetParent(designerItem) as Canvas; + + if (canvas != null) + { + centerPoint = designerItem.TranslatePoint( + new Point(designerItem.ActualWidth * designerItem.RenderTransformOrigin.X, + designerItem.ActualHeight * designerItem.RenderTransformOrigin.Y), + canvas); + + Point startPoint = Mouse.GetPosition(canvas); + startVector = Point.Subtract(startPoint, centerPoint); + + rotateTransform = designerItem.RenderTransform as RotateTransform; + if (rotateTransform == null) + { + designerItem.RenderTransform = new RotateTransform(0); + initialAngle = 0; + } + else + { + initialAngle = rotateTransform.Angle; + } + } + } + } + + private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e) + { + if (designerItem != null && canvas != null) + { + Point currentPoint = Mouse.GetPosition(canvas); + Vector deltaVector = Point.Subtract(currentPoint, centerPoint); + + double angle = Vector.AngleBetween(startVector, deltaVector); + + RotateTransform rotateTransform = designerItem.RenderTransform as RotateTransform; + rotateTransform.Angle = initialAngle + Math.Round(angle, 0); + designerItem.InvalidateMeasure(); + } + } + } +} diff --git a/BrightSharp.NET/Diagrams/VisualExtensions.cs b/BrightSharp.NET/Diagrams/VisualExtensions.cs new file mode 100644 index 0000000..e30c652 --- /dev/null +++ b/BrightSharp.NET/Diagrams/VisualExtensions.cs @@ -0,0 +1,132 @@ +using BrightSharp.Extensions; +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Animation; + +namespace BrightSharp.Diagrams +{ + /// + /// If starts with a(A) then use animation, + /// $FromZoom-$ToZoom pattern + /// + public class VisualExtensions : DependencyObject + { + #region LevelOfDetails Attached Property + + public static readonly DependencyProperty LODZoomProperty = + DependencyProperty.RegisterAttached("LODZoom", + typeof(string), + typeof(VisualExtensions), + new UIPropertyMetadata(null, OnChangeLODZoomProperty)); + + public static void SetLODZoom(UIElement element, string o) + { + element.SetValue(LODZoomProperty, o); + } + + public static string GetLODZoom(UIElement element) + { + return (string)element.GetValue(LODZoomProperty); + } + #endregion + + public static bool GetCanRotate(DependencyObject obj) { + return (bool)obj.GetValue(CanRotateProperty); + } + + public static void SetCanRotate(DependencyObject obj, bool value) { + obj.SetValue(CanRotateProperty, value); + } + + public static readonly DependencyProperty CanRotateProperty = + DependencyProperty.RegisterAttached("CanRotate", typeof(bool), typeof(VisualExtensions), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); + + private static void OnChangeLODZoomProperty(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var element = d as FrameworkElement; + if (element == null) return; + + var window = Window.GetWindow(element); + if (window == null) return; + + if (e.NewValue != e.OldValue) + { + var zoomControl = element.FindAncestor(); + if (zoomControl == null) return; + + var zoomChangedHandler = new RoutedEventHandler((sender, args) => + { + try { + ChangeVisibility(args, element, window); + } + catch (Exception) { + } + }); + + + if (string.IsNullOrWhiteSpace((string)e.NewValue)) + { + element.Opacity = 1; + zoomControl.ZoomChanged -= zoomChangedHandler; + zoomControl.Loaded -= zoomChangedHandler; + } + else + { + zoomControl.ZoomChanged += zoomChangedHandler; + zoomControl.Loaded += zoomChangedHandler; + } + } + } + + private static void ChangeVisibility(RoutedEventArgs args, FrameworkElement element, Window window) { + var lodInfo = new LodInfo(GetLODZoom(element)); + + var transform = element.TransformToVisual(window) as MatrixTransform; + var scaleX = transform.Matrix.M11; + + var newOpacity = (scaleX >= lodInfo.StartRange && scaleX <= lodInfo.EndRange) ? 1 : 0; + + if (lodInfo.UseAnimation && args.RoutedEvent != FrameworkElement.LoadedEvent) { + element.Visibility = Visibility.Visible; + var animation = new DoubleAnimation(newOpacity, TimeSpan.FromSeconds(.5)); + element.BeginAnimation(UIElement.OpacityProperty, animation); + } + else { + element.Visibility = newOpacity == 1 ? Visibility.Visible : Visibility.Hidden; + element.Opacity = newOpacity; + } + } + + sealed class LodInfo + { + public LodInfo(string lod) + { + lod = lod.TrimStart(); + UseAnimation = lod.StartsWith("a", true, CultureInfo.InvariantCulture); + lod = lod.TrimStart('a', 'A').Trim(); + + double rangeStart = 0; + double rangeEnd = double.PositiveInfinity; + var vals = lod.Split('-'); + + double.TryParse(vals[0], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rangeStart); + + if (vals.Length > 1) + { + if (!double.TryParse(vals[1], NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out rangeEnd)) + { + rangeEnd = double.PositiveInfinity; + } + } + EndRange = rangeEnd; + StartRange = rangeStart; + } + public double StartRange { get; set; } + public double EndRange { get; set; } + public bool UseAnimation { get; set; } + } + } + +} diff --git a/BrightSharp.NET/Diagrams/ZoomControl.cs b/BrightSharp.NET/Diagrams/ZoomControl.cs new file mode 100644 index 0000000..287d689 --- /dev/null +++ b/BrightSharp.NET/Diagrams/ZoomControl.cs @@ -0,0 +1,228 @@ +using BrightSharp.Extensions; +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media.Animation; + +namespace BrightSharp.Diagrams +{ + + public partial class ZoomControl : ItemsControl + { + public ZoomControl() + { + Loaded += ZoomControl_Loaded; + + } + + private void ZoomControl_Loaded(object sender, RoutedEventArgs e) + { + SelectionBehavior.Attach(this); + } + + public ContentControl SelectedControl + { + get { return (ContentControl)GetValue(SelectedControlProperty); } + set { SetValue(SelectedControlProperty, value); } + } + + public static readonly DependencyProperty SelectedControlProperty = + DependencyProperty.Register("SelectedControl", typeof(ContentControl), typeof(ZoomControl), new PropertyMetadata(null)); + + protected override void OnPreviewMouseDown(MouseButtonEventArgs e) + { + base.OnPreviewMouseDown(e); + + if (e.MiddleButton == MouseButtonState.Pressed) + { + _panPoint = e.GetPosition(this); + } + } + + private Point? _panPoint; + + #region Props + + public double TranslateX + { + get { return (double)GetValue(TranslateXProperty); } + set { SetValue(TranslateXProperty, value); } + } + + public static readonly DependencyProperty TranslateXProperty = + DependencyProperty.Register("TranslateX", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange, TranslateChangedHandler)); + + + + public double TranslateY + { + get { return (double)GetValue(TranslateYProperty); } + set { SetValue(TranslateYProperty, value); } + } + + public static readonly DependencyProperty TranslateYProperty = + DependencyProperty.Register("TranslateY", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange, TranslateChangedHandler)); + + + + public double GridSize + { + get { return (double)GetValue(GridSizeProperty); } + set { SetValue(GridSizeProperty, value); } + } + + public static readonly DependencyProperty GridSizeProperty = + DependencyProperty.Register("GridSize", typeof(double), typeof(ZoomControl), new PropertyMetadata(0.0)); + + public double RenderZoom + { + get { return (double)GetValue(RenderZoomProperty); } + set { SetValue(RenderZoomProperty, value); } + } + + public static readonly DependencyProperty RenderZoomProperty = + DependencyProperty.Register("RenderZoom", typeof(double), typeof(ZoomControl), new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsArrange, ZoomChangedHandler)); + + private static void ZoomChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs baseValue) + { + ZoomControl zc = (ZoomControl)d; + } + private static void TranslateChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs baseValue) + { + ZoomControl zc = (ZoomControl)d; + } + + #endregion + + private static readonly RoutedEvent ZoomChangedEvent = EventManager.RegisterRoutedEvent("ZoomChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ZoomControl)); + + public event RoutedEventHandler ZoomChanged + { + add { AddHandler(ZoomChangedEvent, value); } + remove { RemoveHandler(ZoomChangedEvent, value); } + } + + private void RaiseZoomChangedEvent() + { + var newEventArgs = new RoutedEventArgs(ZoomChangedEvent); + RaiseEvent(newEventArgs); + } + + static ZoomControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(ZoomControl), new FrameworkPropertyMetadata(typeof(ZoomControl))); + } + + protected override void OnPreviewMouseWheel(MouseWheelEventArgs e) + { + if (CheckMouseOverControlWheelHandle(_panPoint.HasValue)) + return; + + var point = e.GetPosition(this); + + + var oldValue = RenderZoom; + const double zoomPower = 1.25; + var newValue = RenderZoom * (e.Delta > 0 ? zoomPower : 1 / zoomPower); + if (UseAnimation) + { + DoubleAnimation anim = new DoubleAnimation(newValue, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.RenderZoomProperty, anim); + } + else + { + DoubleAnimation anim = new DoubleAnimation(newValue, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.RenderZoomProperty, anim); + } + + RaiseZoomChangedEvent(); + + var translateXTo = CoercePanTranslate(TranslateX, point.X, oldValue, newValue); + var translateYTo = CoercePanTranslate(TranslateY, point.Y, oldValue, newValue); + if (UseAnimation) + { + DoubleAnimation anim = new DoubleAnimation(translateXTo, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateXProperty, anim); + + anim = new DoubleAnimation(translateYTo, TimeSpan.FromSeconds(.3)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateYProperty, anim); + } + else + { + DoubleAnimation anim = new DoubleAnimation(translateXTo, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateXProperty, anim); + + anim = new DoubleAnimation(translateYTo, TimeSpan.FromSeconds(0)); + anim.EasingFunction = new SineEase() { EasingMode = EasingMode.EaseInOut }; + BeginAnimation(ZoomControl.TranslateYProperty, anim); + } + + e.Handled = true; + + base.OnPreviewMouseWheel(e); + } + public bool UseAnimation { get; set; } + private static bool CheckMouseOverControlWheelHandle(bool checkFlowDoc = false) + { + if (Keyboard.IsKeyDown(Key.LeftCtrl)) return false; + var element = Mouse.DirectlyOver as DependencyObject; + if (element is ScrollViewer) return true; + + var scrollViewer = element.FindAncestor(); + if (scrollViewer != null) + { + return scrollViewer.ComputedVerticalScrollBarVisibility == Visibility.Visible + || scrollViewer.ComputedHorizontalScrollBarVisibility == Visibility.Visible; + } + if (checkFlowDoc) + { + var flowDocument = element.FindAncestor(); + if (flowDocument != null) + { + return true; + } + } + + return false; + } + + private static double CoercePanTranslate(double oldTranslate, double mousePos, double oldZoom, double newZoom) + { + return Math.Round(oldTranslate + (oldTranslate - mousePos) * (newZoom - oldZoom) / oldZoom); + } + + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + + if (e.MiddleButton == MouseButtonState.Released) + { + _panPoint = null; + ReleaseMouseCapture(); + } + } + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + if (e.MiddleButton == MouseButtonState.Pressed && _panPoint.HasValue) + { + //PAN MODE + var vector = e.GetPosition(this) - _panPoint.Value; + _panPoint = _panPoint + vector; + CaptureMouse(); + TranslateX += vector.X; + TranslateY += vector.Y; + BeginAnimation(TranslateXProperty, null); + BeginAnimation(TranslateYProperty, null); + } + } + + } +} diff --git a/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs b/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs new file mode 100644 index 0000000..02650ea --- /dev/null +++ b/BrightSharp.NET/Extensions/MarkupExtensionProperties.cs @@ -0,0 +1,168 @@ +using BrightSharp.Behaviors; +using System; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace BrightSharp.Extensions +{ + public static class MarkupExtensionProperties + { + public static CornerRadius GetCornerRadius(DependencyObject obj) + { + return (CornerRadius)obj.GetValue(CornerRadiusProperty); + } + public static void SetCornerRadius(DependencyObject obj, CornerRadius value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetHeader(DependencyObject obj) + { + return obj.GetValue(HeaderProperty); + } + public static void SetHeader(DependencyObject obj, object value) + { + obj.SetValue(HeaderProperty, value); + } + public static object GetLeadingElement(DependencyObject obj) + { + return obj.GetValue(CornerRadiusProperty); + } + public static void SetLeadingElement(DependencyObject obj, object value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetTrailingElement(DependencyObject obj) + { + return obj.GetValue(CornerRadiusProperty); + } + public static void SetTrailingElement(DependencyObject obj, object value) + { + obj.SetValue(CornerRadiusProperty, value); + } + public static object GetIcon(DependencyObject obj) + { + return obj.GetValue(IconProperty); + } + public static void SetIcon(DependencyObject obj, object value) + { + obj.SetValue(IconProperty, value); + } + public static void SetHeaderHeight(DependencyObject obj, double value) + { + obj.SetValue(HeaderHeightProperty, value); + } + public static double GetHeaderHeight(DependencyObject obj) + { + return (double)obj.GetValue(HeaderHeightProperty); + } + + public static void SetHeaderVerticalAlignment(DependencyObject obj, VerticalAlignment value) + { + obj.SetValue(HeaderVerticalAlignmentProperty, value); + } + public static VerticalAlignment GetHeaderVerticalAlignment(DependencyObject obj) + { + return (VerticalAlignment)obj.GetValue(HeaderVerticalAlignmentProperty); + } + public static void SetHeaderHorizontalAlignment(DependencyObject obj, HorizontalAlignment value) + { + obj.SetValue(HeaderHorizontalAlignmentProperty, value); + } + public static HorizontalAlignment GetHeaderHorizontalAlignment(DependencyObject obj) + { + return (HorizontalAlignment)obj.GetValue(HeaderHorizontalAlignmentProperty); + } + public static void SetSpecialHeight(DependencyObject obj, double value) + { + obj.SetValue(SpecialHeightProperty, value); + } + public static double GetSpecialHeight(DependencyObject obj) + { + return (double)obj.GetValue(SpecialHeightProperty); + } + public static void SetSpecialWidth(DependencyObject obj, double value) + { + obj.SetValue(SpecialWidthProperty, value); + } + public static double GetSpecialWidth(DependencyObject obj) + { + return (double)obj.GetValue(SpecialWidthProperty); + } + public static Dock GetDocking(DependencyObject obj) + { + return (Dock)obj.GetValue(DockingProperty); + } + public static void SetDocking(DependencyObject obj, Dock value) + { + obj.SetValue(DockingProperty, value); + } + public static Thickness GetHeaderPadding(DependencyObject obj) + { + return (Thickness)obj.GetValue(HeaderPaddingProperty); + } + public static void SetHeaderPadding(DependencyObject obj, Thickness value) + { + obj.SetValue(HeaderPaddingProperty, value); + } + public static bool GetIsDragHelperVisible(DependencyObject obj) + { + return (bool)obj.GetValue(IsDragHelperVisibleProperty); + } + public static void SetIsDragHelperVisible(DependencyObject obj, bool value) + { + obj.SetValue(IsDragHelperVisibleProperty, value); + } + public static Brush GetSpecialBrush(DependencyObject obj) + { + return (Brush)obj.GetValue(SpecialBrushProperty); + } + public static void SetSpecialBrush(DependencyObject obj, Brush value) + { + obj.SetValue(SpecialBrushProperty, value); + } + + public static bool GetUseMinMaxSizeBehavior(Window obj) + { + return (bool)obj.GetValue(UseMinMaxSizeBehaviorProperty); + } + + public static void SetUseMinMaxSizeBehavior(Window obj, bool value) + { + obj.SetValue(UseMinMaxSizeBehaviorProperty, value); + } + + public static readonly DependencyProperty SpecialBrushProperty = DependencyProperty.RegisterAttached("SpecialBrush", typeof(Brush), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty IsDragHelperVisibleProperty = DependencyProperty.RegisterAttached("IsDragHelperVisible", typeof(bool), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(true)); + public static readonly DependencyProperty HeaderPaddingProperty = DependencyProperty.RegisterAttached("HeaderPadding", typeof(Thickness), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty LeadingElementProperty = DependencyProperty.RegisterAttached("LeadingElement", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty TrailingElementProperty = DependencyProperty.RegisterAttached("TrailingElement", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached("Header", typeof(object), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(null)); + public static readonly DependencyProperty DockingProperty = DependencyProperty.RegisterAttached("Docking", typeof(Dock), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty IconProperty = DependencyProperty.RegisterAttached("Icon", typeof(object), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderHeightProperty = DependencyProperty.RegisterAttached("HeaderHeight", typeof(double), typeof(MarkupExtensionProperties), new PropertyMetadata(null)); + public static readonly DependencyProperty HeaderVerticalAlignmentProperty = DependencyProperty.RegisterAttached("HeaderVerticalAlignment", typeof(VerticalAlignment), typeof(MarkupExtensionProperties), new PropertyMetadata(VerticalAlignment.Center)); + public static readonly DependencyProperty HeaderHorizontalAlignmentProperty = DependencyProperty.RegisterAttached("HeaderHorizontalAlignment", typeof(HorizontalAlignment), typeof(MarkupExtensionProperties), new PropertyMetadata(HorizontalAlignment.Left)); + public static readonly DependencyProperty SpecialHeightProperty = DependencyProperty.RegisterAttached("SpecialHeight", typeof(double), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); + public static readonly DependencyProperty SpecialWidthProperty = DependencyProperty.RegisterAttached("SpecialWidth", typeof(double), typeof(MarkupExtensionProperties), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure)); + public static readonly DependencyProperty UseMinMaxSizeBehaviorProperty = DependencyProperty.RegisterAttached("UseMinMaxSizeBehavior", typeof(bool), typeof(MarkupExtensionProperties), new PropertyMetadata(false, UseMinMaxSizeBehaviorChanged)); + + + private static void UseMinMaxSizeBehaviorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var window = d as Window; + if (window == null) return; + if ((bool)e.NewValue) + { + new MinMaxSize_Logic(window).OnAttached(); + } + else + { + // Not supported yet + } + } + } + +} diff --git a/BrightSharp.NET/Extensions/WpfExtensions.cs b/BrightSharp.NET/Extensions/WpfExtensions.cs new file mode 100644 index 0000000..9e0f579 --- /dev/null +++ b/BrightSharp.NET/Extensions/WpfExtensions.cs @@ -0,0 +1,142 @@ +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Media3D; + +namespace BrightSharp.Extensions +{ + public static class WpfExtensions + { + /// + /// Returns Parent item of DependencyObject + /// + /// Child object + /// Prefer LogicalTree when need. + /// Found item + public static DependencyObject GetParent(this DependencyObject obj, bool useLogicalTree = false) + { + if (!useLogicalTree && (obj is Visual || obj is Visual3D)) + return VisualTreeHelper.GetParent(obj) ?? LogicalTreeHelper.GetParent(obj); + else + return LogicalTreeHelper.GetParent(obj); + } + + public static IEnumerable GetAncestors(this DependencyObject obj, bool useLogicalTree = false) where T : DependencyObject + { + if (obj == null) yield break; + + var x = GetParent(obj, useLogicalTree); + + while (x != null && !(x is T)) + { + x = GetParent(x, useLogicalTree); + } + if (x != null) + yield return x as T; + else + yield break; + foreach (var item in GetAncestors(x, useLogicalTree)) + { + yield return item; + } + } + + public static T FindAncestor(this DependencyObject obj) where T : DependencyObject + { + return GetAncestors(obj).FirstOrDefault(); + } + + /// + /// Try find ItemsPanel of ItemsControl + /// + /// Where to search + /// Panel of ItemsControl + public static Panel GetItemsPanel(DependencyObject itemsControl) + { + if (itemsControl is Panel) return (Panel)itemsControl; + ItemsPresenter itemsPresenter = FindVisualChildren(itemsControl).FirstOrDefault(); + if (itemsPresenter == null) return null; + var itemsPanel = VisualTreeHelper.GetChild(itemsPresenter, 0) as Panel; + return itemsPanel; + } + + /// + /// Check if object is valid (no errors found in logical children) + /// + /// Object to search + /// True if no errors found + public static bool IsValid(this DependencyObject obj) { + if (obj == null) return true; + if (Validation.GetHasError(obj)) return false; + foreach (var child in LogicalTreeHelper.GetChildren(obj).OfType()) { + if (child == null) continue; + if (child is UIElement ui) { + if (!ui.IsVisible || !ui.IsEnabled) continue; + } + if (!IsValid(child)) return false; + } + return true; + } + + /// + /// Search all textboxes to update invalid with UpdateSource(). For ex. when need update validation messages. + /// + /// Object where to search TextBoxes + public static void UpdateSources(this DependencyObject obj) { + if (obj == null) return; + if (Validation.GetHasError(obj)) { + //TODO Any types? + if (obj is TextBox tb) tb.GetBindingExpression(TextBox.TextProperty)?.UpdateSource(); + } + foreach (var item in FindLogicalChildren(obj)) { + UpdateSources(item); + } + } + + /// + /// Find all visual children of type T + /// + /// Type to search + /// Object where to search + /// Enumerator for items + public static IEnumerable FindVisualChildren(this DependencyObject depObj) where T : DependencyObject { + if (depObj != null && (depObj is Visual || depObj is Visual3D)) { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { + DependencyObject child = VisualTreeHelper.GetChild(depObj, i); + if (child != null && child is T) { + yield return (T)child; + } + + foreach (T childOfChild in FindVisualChildren(child)) { + yield return childOfChild; + } + } + } + } + + /// + /// Find all logical children of type T + /// + /// Type to search + /// Object where to search + /// Enumerator for items + public static IEnumerable FindLogicalChildren(this DependencyObject depObj) where T : DependencyObject { + if (depObj != null) { + foreach (object rawChild in LogicalTreeHelper.GetChildren(depObj)) { + if (rawChild is DependencyObject child) { + if (child is T) { + yield return (T)child; + } + + foreach (T childOfChild in FindLogicalChildren(child)) { + yield return childOfChild; + } + } + } + } + } + } + +} diff --git a/BrightSharp.NET/Interop/Constants.cs b/BrightSharp.NET/Interop/Constants.cs new file mode 100644 index 0000000..d18d5fe --- /dev/null +++ b/BrightSharp.NET/Interop/Constants.cs @@ -0,0 +1,11 @@ +namespace BrightSharp.Interop +{ + namespace Constants + { + internal enum MonitorFromWindowFlags + { + MONITOR_DEFAULTTONEAREST = 0x00000002 + } + + } +} diff --git a/BrightSharp.NET/Interop/NativeMethods.cs b/BrightSharp.NET/Interop/NativeMethods.cs new file mode 100644 index 0000000..2c75530 --- /dev/null +++ b/BrightSharp.NET/Interop/NativeMethods.cs @@ -0,0 +1,20 @@ +using BrightSharp.Interop.Structures; +using System; +using System.Runtime.InteropServices; + +namespace BrightSharp.Interop +{ + internal static class NativeMethods + { + #region Monitor + + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); + + [DllImport("user32.dll", SetLastError = true)] + internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); + + #endregion + + } +} diff --git a/BrightSharp.NET/Interop/Structures.cs b/BrightSharp.NET/Interop/Structures.cs new file mode 100644 index 0000000..16a6ef2 --- /dev/null +++ b/BrightSharp.NET/Interop/Structures.cs @@ -0,0 +1,130 @@ +using System; +using System.Runtime.InteropServices; + +namespace BrightSharp.Interop +{ + namespace Structures + { + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + + public RECT rcMonitor; + + public RECT rcWork; + + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal struct POINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential, Pack = 0)] + internal struct RECT + { + public int Left; + + public int Top; + + public int Right; + + public int Bottom; + + public static readonly RECT Empty; + + public int Width + { + get { + return Math.Abs(Right - Left); + } // Abs needed for BIDI OS + } + + public int Height + { + get { + return Bottom - Top; + } + } + + public RECT(int left, int top, int right, int bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + public RECT(RECT rcSrc) + { + Left = rcSrc.Left; + Top = rcSrc.Top; + Right = rcSrc.Right; + Bottom = rcSrc.Bottom; + } + + public bool IsEmpty + { + get { + // BUGBUG : On Bidi OS (hebrew arabic) left > right + return Left >= Right || Top >= Bottom; + } + } + + public override string ToString() + { + if (this == Empty) + { + return "RECT {Empty}"; + } + return "RECT { left : " + Left + " / top : " + Top + " / right : " + Right + " / bottom : " + + Bottom + " }"; + } + + public override bool Equals(object obj) + { + if (!(obj is RECT)) + { + return false; + } + return (this == (RECT)obj); + } + + public override int GetHashCode() + { + return Left.GetHashCode() + Top.GetHashCode() + Right.GetHashCode() + + Bottom.GetHashCode(); + } + + public static bool operator ==(RECT rect1, RECT rect2) + { + return (rect1.Left == rect2.Left && rect1.Top == rect2.Top && rect1.Right == rect2.Right && + rect1.Bottom == rect2.Bottom); + } + + public static bool operator !=(RECT rect1, RECT rect2) + { + return !(rect1 == rect2); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + public POINT ptReserved; + + public POINT ptMaxSize; + + public POINT ptMaxPosition; + + public POINT ptMinTrackSize; + + public POINT ptMaxTrackSize; + }; + } +} diff --git a/BrightSharp.NET/Properties/AssemblyInfo.cs b/BrightSharp.NET/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9678de3 --- /dev/null +++ b/BrightSharp.NET/Properties/AssemblyInfo.cs @@ -0,0 +1,63 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Markup; + +// 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("BrightSharp")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BrightSharp")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[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("2.0.0.0")] +[assembly: AssemblyFileVersion("2.0.0.0")] +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/developer", "bs")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Extensions")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Behaviors")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/developer", "BrightSharp.Converters")] + + +[assembly: XmlnsPrefix("http://schemas.brightsharp.com/diagrams", "bsDiag")] +[assembly: XmlnsDefinition("http://schemas.brightsharp.com/diagrams", "BrightSharp.Diagrams")] \ No newline at end of file diff --git a/BrightSharp.NET/Properties/Resources.Designer.cs b/BrightSharp.NET/Properties/Resources.Designer.cs new file mode 100644 index 0000000..fa62214 --- /dev/null +++ b/BrightSharp.NET/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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 BrightSharp.Properties { + using System; + + + /// + /// 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", "15.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 (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BrightSharp.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/BrightSharp.NET/Properties/Resources.resx b/BrightSharp.NET/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/BrightSharp.NET/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/BrightSharp.NET/Properties/Settings.Designer.cs b/BrightSharp.NET/Properties/Settings.Designer.cs new file mode 100644 index 0000000..1a76537 --- /dev/null +++ b/BrightSharp.NET/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 BrightSharp.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.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/BrightSharp.NET/Properties/Settings.settings b/BrightSharp.NET/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/BrightSharp.NET/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Controls/ZoomControl.xaml b/BrightSharp.NET/Themes/Controls/ZoomControl.xaml new file mode 100644 index 0000000..991346d --- /dev/null +++ b/BrightSharp.NET/Themes/Controls/ZoomControl.xaml @@ -0,0 +1,38 @@ + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml b/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml new file mode 100644 index 0000000..4028bcd --- /dev/null +++ b/BrightSharp.NET/Themes/Diagrams/DesignerItem.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml b/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml new file mode 100644 index 0000000..ae89737 --- /dev/null +++ b/BrightSharp.NET/Themes/Diagrams/ResizeRotateChrome.xaml @@ -0,0 +1,114 @@ + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml b/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml new file mode 100644 index 0000000..cdae020 --- /dev/null +++ b/BrightSharp.NET/Themes/Diagrams/SizeChrome.xaml @@ -0,0 +1,49 @@ + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Generic.xaml b/BrightSharp.NET/Themes/Generic.xaml new file mode 100644 index 0000000..63b9319 --- /dev/null +++ b/BrightSharp.NET/Themes/Generic.xaml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Style.Blue.xaml b/BrightSharp.NET/Themes/Style.Blue.xaml new file mode 100644 index 0000000..847e392 --- /dev/null +++ b/BrightSharp.NET/Themes/Style.Blue.xaml @@ -0,0 +1,326 @@ + + + False + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + + + #FF1B140F + #FFB6B6B6 + + + #FFFFF8B8 + + + Black + + + + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + #FFDADCEC + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Style.Classic.xaml b/BrightSharp.NET/Themes/Style.Classic.xaml new file mode 100644 index 0000000..b299435 --- /dev/null +++ b/BrightSharp.NET/Themes/Style.Classic.xaml @@ -0,0 +1,283 @@ + + + + + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + Black + + + + + + + + + + + + + #E0E0EA + Black + #FAE0A0 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + #FFDADCEC + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Style.DarkBlue.xaml b/BrightSharp.NET/Themes/Style.DarkBlue.xaml new file mode 100644 index 0000000..ac18d2a --- /dev/null +++ b/BrightSharp.NET/Themes/Style.DarkBlue.xaml @@ -0,0 +1,307 @@ + + + True + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + + #99BDFF + #999999 + #FF2F596E + #FF10405B + #FF2B404B + + #FF414888 + #FF47909B + #D6D6D6 + #E6E6E6 + + #FF3333 + + #ffffff + + #555555 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + White + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Style.DevLab.xaml b/BrightSharp.NET/Themes/Style.DevLab.xaml new file mode 100644 index 0000000..4f6422d --- /dev/null +++ b/BrightSharp.NET/Themes/Style.DevLab.xaml @@ -0,0 +1,274 @@ + + + False + + 0 + 1 + + + 0 + 0 + 0 + 0 + 0,2,0,0 + + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + White + + + + + + Black + + + + + + + + + + + + + + + + + + + + Black + + + + + + + + #E3E3E3 + #FFD6E6E6 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + + #FFEEEEEE + #FF47909B + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Style.Silver.xaml b/BrightSharp.NET/Themes/Style.Silver.xaml new file mode 100644 index 0000000..a0e1f31 --- /dev/null +++ b/BrightSharp.NET/Themes/Style.Silver.xaml @@ -0,0 +1,324 @@ + + + False + + 1 + 3 + + 0,8,0,0 + 0,2,2,2 + 0,5,5,0 + 5,0,0,5 + 5,5,0,0 + + Red + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #FFF + + + + + + + + + + + Black + + + + + + + + + + + + + + + + + + + + + + + + + + + + Black + + + + + + #DEDEDE + #FFB6B6B6 + #FFFFFFFF + #FFC5C5C5 + #FF6B6B6B + + #FFCED0E1 + #FF47909B + + #D6D6D6 + #E6E6E6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Theme.Static.cs b/BrightSharp.NET/Themes/Theme.Static.cs new file mode 100644 index 0000000..574476a --- /dev/null +++ b/BrightSharp.NET/Themes/Theme.Static.cs @@ -0,0 +1,41 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Themes +{ + + internal partial class ThemeStatic + { + public void CalendarPreviewMouseUp(object sender, MouseEventArgs e) { + if (Mouse.Captured is CalendarItem) { Mouse.Capture(null); } + } + public void DatePickerUnloaded(object sender, RoutedEventArgs e) { + if (sender == null) return; + DependencyObject child = ((Popup)((DatePicker)sender).Template.FindName("PART_Popup", (FrameworkElement)sender))?.Child; + while (child != null && !(child is AdornerDecorator)) + child = VisualTreeHelper.GetParent(child) ?? LogicalTreeHelper.GetParent(child); + if (((AdornerDecorator)child)?.Child is Calendar) ((AdornerDecorator)child).Child = null; + } + + + private void closeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.Close(); + } + + private void maximizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = window.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; + } + + private void minimizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = WindowState.Minimized; + } + } +} diff --git a/BrightSharp.NET/Themes/Theme.Static.xaml b/BrightSharp.NET/Themes/Theme.Static.xaml new file mode 100644 index 0000000..c7eb0bd --- /dev/null +++ b/BrightSharp.NET/Themes/Theme.Static.xaml @@ -0,0 +1,5729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BrightSharp.NET/Themes/Theme.cs b/BrightSharp.NET/Themes/Theme.cs new file mode 100644 index 0000000..219a1a3 --- /dev/null +++ b/BrightSharp.NET/Themes/Theme.cs @@ -0,0 +1,40 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace BrightSharp.Themes +{ + + internal partial class Theme + { + public void CalendarPreviewMouseUp(object sender, MouseEventArgs e) { + if (Mouse.Captured is CalendarItem) { Mouse.Capture(null); } + } + public void DatePickerUnloaded(object sender, RoutedEventArgs e) { + if (sender == null) return; + DependencyObject child = ((Popup)((DatePicker)sender).Template.FindName("PART_Popup", (FrameworkElement)sender))?.Child; + while (child != null && !(child is AdornerDecorator)) + child = VisualTreeHelper.GetParent(child) ?? LogicalTreeHelper.GetParent(child); + if (((AdornerDecorator)child)?.Child is Calendar) ((AdornerDecorator)child).Child = null; + } + + + private void closeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.Close(); + } + + private void maximizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = window.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; + } + + private void minimizeButton_Click(object sender, RoutedEventArgs e) { + var window = Window.GetWindow((DependencyObject)sender); + window.WindowState = WindowState.Minimized; + } + } +} diff --git a/BrightSharp.NET/Themes/Theme.xaml b/BrightSharp.NET/Themes/Theme.xaml new file mode 100644 index 0000000..d32d396 --- /dev/null +++ b/BrightSharp.NET/Themes/Theme.xaml @@ -0,0 +1,5760 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BrightSharp.NET/Themes/ThemeManager.cs b/BrightSharp.NET/Themes/ThemeManager.cs new file mode 100644 index 0000000..0df032b --- /dev/null +++ b/BrightSharp.NET/Themes/ThemeManager.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Threading; + +namespace BrightSharp.Themes +{ + public enum ColorThemes + { + Classic, + DevLab, + Silver, + Blue, + DarkBlue + } + + public static class ThemeManager + { + private const string StyleDictionaryPattern = @"(?<=.+style\.)(.*?)(?=\.xaml)"; + private const string ThemeDictionaryUri = "/brightsharp;component/themes/theme.xaml"; + + private static ColorThemes? ThemeField; + + public static ColorThemes? Theme + { + get { + if (ThemeField.HasValue) return ThemeField.Value; + var curStyleRes = Resources.Where(r => r.Source != null && + Regex.IsMatch(r.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase)).FirstOrDefault(); + if (curStyleRes == null) return null; + var match = Regex.Match(curStyleRes.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase); + ThemeField = (ColorThemes)Enum.Parse(typeof(ColorThemes), match.Value, true); + return ThemeField.Value; + } + set { + _ = SetTheme(value); + } + } + + public static async Task SetTheme(ColorThemes? value, DispatcherPriority priority = DispatcherPriority.Background) + { + if (ThemeField == value) { return; } + ThemeField = value; + await Application.Current.Dispatcher.InvokeAsync(() => + { + if (ThemeField != value) return; + Application.Current.Resources.BeginInit(); + + var curStyleRes = Resources.Where(r => r.Source != null && + Regex.IsMatch(r.Source.OriginalString, StyleDictionaryPattern, RegexOptions.IgnoreCase)).FirstOrDefault(); + var curThemeRes = Resources.Where(r => r.Source != null && r.Source.OriginalString.Equals(ThemeDictionaryUri, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (curThemeRes != null) + Resources.Remove(curThemeRes); + if (curStyleRes != null) + Resources.Remove(curStyleRes); + if (value == null) return; + Resources.Add(new ResourceDictionary() { Source = new Uri($"/brightsharp;component/themes/style.{value}.xaml", UriKind.RelativeOrAbsolute) }); + Resources.Add(new ResourceDictionary() { Source = new Uri(ThemeDictionaryUri, UriKind.RelativeOrAbsolute) }); + + Application.Current.Resources.EndInit(); + ThemeChanged?.Invoke(null, EventArgs.Empty); + }, priority); + } + + public static event EventHandler ThemeChanged; + + private static ICollection Resources + { + get { return Application.Current.Resources.MergedDictionaries; } + } + } + +} diff --git a/BrightSharp.NET/Themes/icons/app.png b/BrightSharp.NET/Themes/icons/app.png new file mode 100644 index 0000000000000000000000000000000000000000..9d372aab5d774bce956282d581c83c98fdd4782f GIT binary patch literal 367 zcmV-#0g(QQP)7g! zKzG@A0hc1KJ&B8)#icv1;tdRB5!ZqQ@?+G2IO#vDdWf!jQt+l=nD2GHqDRFTaY)h4 z)8dxuU}F^4WUwwZR)q$(el(hW zKn&{7Wm9by42O{9z5nZb@dL;FZpi(-`>uL<`>Kh`5|4K$z4CK>kasSfmb*-)6ogF% z`;l`>Yuy<*YyWd*lraXvCIiP#qMVY*oxyIGPR})v9SBRdZIgjzx7-~FOSb0(L2urK!^W@@w-s>X8hZd!RBC_pIuG6o!jG4^&*E+0c2tVTm^g5x*}*Pr6fbER}%cyG7EAl%n#kj-Y{ zv{<};Z8je^5l9tGq(PD)AUw+DG|7!=0$MatiAihBw`QTWE4}gAvb5Z8*HKRQQ;&ne zaLLMJy}r>J52OewKo|m~Az}72gRfpshhJ9(ADzxRYcC;zloEsxI%pmQL@Y+F5eX7s zhC8H?vA1O)*=RI|lR`lU!9!)?DayPNxY1ZxoA##q*I_23|4V8bLLy=KO%%mq&99Nv zjpkv)EnOq$e7gc9(iV|H@#Q2Ea}2PWN%9j_K$Ul0SC0p&G*BYWDai@}HpJOowVMB( z&s|*@Jk{^_$G4S=eO@ZTWHNzNGKC6>fQ4^m)#4t;ZX|Y4mD&ai_XM{v{%@NN8@9bq tMN?~vORp7e4Oz_9=c%?35BE=i0RT5r8CncW4OIXD002ovPDHLkV1gUd&$j>o literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/Themes/icons/cut.png b/BrightSharp.NET/Themes/icons/cut.png new file mode 100644 index 0000000000000000000000000000000000000000..9a0ae031ac67c861211043bb9f0c9f51b779e02a GIT binary patch literal 510 zcmV8k}5^aE-thCOJo3~!W_`iSuX885< zHv`cI96WGnp0J>x$d#+tAA|TmfBt0P=HVu200UAWN-tfp>h0^-um4}XcgC743F;|t9!tqU}4dE=0Eel-_IHT z{{G1L?~lfjCMQOmUNG;xtY+4J;lF9qNsyp0$Teo=+xA-3?FU7%wn5_LZoA5Dk8!3% zroVr7eY(20i2d((5ce&}HK#hg(ir~!`ej?atL4J{+-}A{zl1T;0Sqwy`z3#4N%4Hf zKR=O$?;dM)_xStmJ)?d3hL?Z7zdwP~3pNc0!5sVYP1s^U5r~a}SQ(}dBM=#X{{U*< z@c+}pORd-f7m5+;u|%UWlzs@rZ}6o95C8};0RM>OFInyic>n+a07*qoM6N<$f-eU9 A(*OVf literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/Themes/icons/paste.png b/BrightSharp.NET/Themes/icons/paste.png new file mode 100644 index 0000000000000000000000000000000000000000..ee4bd3e94db2a21985dcdf4c54a90b5583f45bd6 GIT binary patch literal 715 zcmV;+0yO=JP)Q562}d-uh5XdBbk zO^X!4Av#qgigc=`RY*WrH#do+T_l4@3r^a(E`m;0(m_Oo#^NG%@P|~FB9@4Q_(Kw3 zUi04l@!b0!FY1s3H@WYgbH4MP?;Q5v#sU}=Tpgk@d>$<7XlMm62ihB9`QQm8%Rs|{ zc~?;vxw)J4AJ}iMl&onbN=io%BEp%I1!!_G0(iOgMo09f7^82#&LGQ>k@XXzH7=s4 zbn$WpOoeD}{6ubI5(EmzaWFbEigNiX0eEqGn*G32hh&Y>B?po2&P0;X3NjQadBd=!^1%wdo{ zuGLE1FbVw*LP1gSHJ$9Z(A$$|2#BAkZC2k3;)1 zxVO5BeEwLPTsVEo`b-2jzk7b0a$@wDff*ySK_2%|sa&&n<2O|WF^mz+c8~^v-y#hZ zA{t*r)k7iDK0VLF%F11AzNmw9j(UBA-gxTgre@G>Q&CdZ&^Fs9RT|)O7uOdTQwGKP zd15R30JeorD|t)+h+@)#Ww5-ogcCC}P*lLgohugm07eMEO8`2N#RL%>FF|l=-qmU~ zO)wh7TA9Hx@ZVjr+5GfvHrA9`24c_0Vb_UQ)p7ory%E>7V~u^L%ru?s|4UMP`uv&d xb;qUZkMu7TIOaG`hYeV?<3<7uHu*<@0RVmFQ(}77sv-aY002ovPDHLkV1i5dKS2Nh literal 0 HcmV?d00001 diff --git a/BrightSharp.NET/Themes/icons/undo.png b/BrightSharp.NET/Themes/icons/undo.png new file mode 100644 index 0000000000000000000000000000000000000000..0c196ec096e723d2074006e40215e54a4046817d GIT binary patch literal 1307 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n3Xa^B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%uvD1M9IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5 zFD$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;NpiyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr4|esh*)icxGNo zet9uiy|1s8XI^nhVqS8pr;Du;&;-5A%oHn2V^ecO3kx$t14lzcLsw%*0~d2Q0~b>Z zXA3uDGe=99UYGpj(%jU%5}4i;gkE!;dO=Acw*Y9fOKMSOS!#+~QGTuh*vnR#xZPrc z(>$o&6x?nx#i>^x=oo!a#3DsBObD2IKumbD1#;jCKQ#}S+KYh6dgn2wNCpPReoq(2 zkcwMxf_*hy0!99vtIanu{^a9)%Kzqx2m?)N?MXb+sfQyXPH;&_Mrc^8Zu8nEW~R(- zZ6DaRY0|`-6aGB0?=igG^Wom^b6@vQn9|xC9RIxJT={;#`+KJ^nexMzAzInp-`{#zZ4i^^R01xF?53F3**WOLrrutMR{c?fjt?WOn8YjOW zn7M54{IDkxpBQKV4nMf{ZTEuAsK-q%+h@I6mb!T5sq5Q>ES=L2v~Rv$y+%%@plE8t zp8d^Fb_NBctbgc~9cno3kbCTN^OHIEmbh-uk>*XU{P48OKzQe|!asuL7qe}SJU)5k z<++SE2Af<}TBdB98yWG6|NYc2Pb%){P0L9;TNS%@hji_cCvGBqzRfdtxV(B)QJK1A z>vVVZo+s+(#Uz8T{#}^3{2_0F?Q(8MgG;d|zNKkR7Wk5$s8b@x&7<4$^6bif4@14@ zzh7Hrvn^AX$y+=ri#`4EHW#+Nk^kOoW8l7Ae*L(T>l`DIm2(!>9*q2d(t5%F{SE4j aYz*y^( + + + \ No newline at end of file