diff --git a/AntlrSupport.props b/AntlrSupport.props index 57a5f2e00..27824047b 100644 --- a/AntlrSupport.props +++ b/AntlrSupport.props @@ -1,10 +1,6 @@ - - $(MSBuildProjectDirectory)/obj - $(BaseIntermediateOutputPath)/$(Configuration) + \ No newline at end of file diff --git a/Avalonia.props b/Avalonia.props index 6251618c4..7e6c37e01 100644 --- a/Avalonia.props +++ b/Avalonia.props @@ -1,12 +1,18 @@ + + 11.1.999-cibuild0045870-beta + + + + - - - - + + + + @@ -17,4 +23,4 @@ Designer - \ No newline at end of file + diff --git a/AvaloniaEdit b/AvaloniaEdit index 0f29494c1..e157a49ea 160000 --- a/AvaloniaEdit +++ b/AvaloniaEdit @@ -1 +1 @@ -Subproject commit 0f29494c1446c91e43ba58e6dbd02837a1183d79 +Subproject commit e157a49ea4b8185c4f38597366562f9ee88c30c6 diff --git a/AvaloniaStyles.Desktop/AvaloniaStyles.Desktop.csproj b/AvaloniaStyles.Desktop/AvaloniaStyles.Desktop.csproj new file mode 100644 index 000000000..e00ef64e0 --- /dev/null +++ b/AvaloniaStyles.Desktop/AvaloniaStyles.Desktop.csproj @@ -0,0 +1,22 @@ + + + + WinExe + net8.0 + Debug;Release + AnyCPU + enable + $(WarningsAsErrors),nullable + + + + + + + + + + + + + diff --git a/AvaloniaStyles.Desktop/Program.cs b/AvaloniaStyles.Desktop/Program.cs new file mode 100644 index 000000000..6b967034b --- /dev/null +++ b/AvaloniaStyles.Desktop/Program.cs @@ -0,0 +1,16 @@ +using Avalonia; + +namespace AvaloniaStyles.Desktop; + +public class Program +{ + static void Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + + // App configuration, used by the entry point and previewer + static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); +} \ No newline at end of file diff --git a/AvaloniaStyles/App.xaml b/AvaloniaStyles/App.xaml index 22f278679..fbafe1a4b 100644 --- a/AvaloniaStyles/App.xaml +++ b/AvaloniaStyles/App.xaml @@ -5,4 +5,8 @@ + + + + diff --git a/AvaloniaStyles/App.xaml.cs b/AvaloniaStyles/App.xaml.cs index 70c650d51..d1d4ebd00 100644 --- a/AvaloniaStyles/App.xaml.cs +++ b/AvaloniaStyles/App.xaml.cs @@ -16,20 +16,14 @@ public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) desktop.MainWindow = new MainWindow(); + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainView + { + DataContext = new DemoDataContext() + }; + } base.OnFrameworkInitializationCompleted(); } - - static void Main(string[] args) - => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - - // App configuration, used by the entry point and previewer - static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() - .With(new Win32PlatformOptions - { - OverlayPopups = true, - }) - .UsePlatformDetect() - .LogToTrace(); } } \ No newline at end of file diff --git a/AvaloniaStyles/AvaloniaStyles.csproj b/AvaloniaStyles/AvaloniaStyles.csproj index a9b86af7d..087a49a65 100644 --- a/AvaloniaStyles/AvaloniaStyles.csproj +++ b/AvaloniaStyles/AvaloniaStyles.csproj @@ -1,19 +1,17 @@ - WinExe - net7.0 - win8-x64;osx-x64;linux-x64;osx-arm64;win-x64 + Library + net8.0 Debug;Release AnyCPU enable - nullable + $(WarningsAsErrors),nullable - false - true - ..\bin\$(Configuration)\ + true + @@ -26,6 +24,9 @@ + + + diff --git a/AvaloniaStyles/Controls/AccentSolidColorBrush.cs b/AvaloniaStyles/Controls/AccentSolidColorBrush.cs index ba0e7345a..c26caf120 100644 --- a/AvaloniaStyles/Controls/AccentSolidColorBrush.cs +++ b/AvaloniaStyles/Controls/AccentSolidColorBrush.cs @@ -1,86 +1,55 @@ using Avalonia; using Avalonia.Media; -using Avalonia.Media.Immutable; using Avalonia.Metadata; using AvaloniaStyles.Utils; +using HslColor = AvaloniaStyles.Utils.HslColor; namespace AvaloniaStyles.Controls; -public class AccentSolidColorBrush : Brush, ISolidColorBrush +public class Accent { - public static readonly StyledProperty BaseColorProperty = - AvaloniaProperty.Register(nameof(BaseColor)); - - public static readonly StyledProperty HueProperty = - AvaloniaProperty.Register(nameof(Hue)); - - static AccentSolidColorBrush() - { - AffectsRender(BaseColorProperty); - AffectsRender(HueProperty); - } - - public AccentSolidColorBrush(Color color, double opacity = 1.0) - { - BaseColor = color; - Opacity = opacity; - } - - public AccentSolidColorBrush(uint color) : this(Color.FromUInt32(color)) - { - } - - public AccentSolidColorBrush() - { - Opacity = 1; - } - - /// Gets or sets the color of the brush. - [Content] - public Color BaseColor - { - get => GetValue(BaseColorProperty); - set => SetValue(BaseColorProperty, value); - } - - public HslDiff Hue - { - get => GetValue(HueProperty); - set => SetValue(HueProperty, value); - } - - /// Parses a brush string. - /// The brush string. - /// The . - /// - /// Whereas may return an immutable solid color brush, - /// this method always returns a mutable . - /// - public static AccentSolidColorBrush Parse(string s) - { - ISolidColorBrush solidColorBrush1 = (ISolidColorBrush)Brush.Parse(s); - return !(solidColorBrush1 is AccentSolidColorBrush solidColorBrush2) - ? new AccentSolidColorBrush(solidColorBrush1.Color) - : solidColorBrush2; - } - - public override string ToString() => Color.ToString(); - - /// - public override IBrush ToImmutable() => new ImmutableSolidColorBrush(this); - - public Color Color - { - get - { - var hsl = HslColor.FromRgba(BaseColor).Scale(Hue); - return hsl.ToRgba(); - } - set - { - var hsl = HslColor.FromRgba(value); - //Hue = (float)hsl.H; - BaseColor = value; - } - } + public static readonly StyledProperty BaseColorProperty = + AvaloniaProperty.RegisterAttached("BaseColor"); + + public static readonly StyledProperty HueProperty = + AvaloniaProperty.RegisterAttached("Hue"); + + static Accent() + { + HueProperty.Changed.AddClassHandler((brush, e) => + { + Color baseColor; + if (!brush.IsSet(BaseColorProperty)) + { + baseColor = brush.Color; + SetBaseColor(brush, baseColor); + } + else + { + baseColor = brush.GetValue(BaseColorProperty); + } + var hsl = HslColor.FromRgba(baseColor).Scale(e.NewValue as HslDiff); + brush.Color = hsl.ToRgba(); + }); + } + + public static Color GetBaseColor(AvaloniaObject obj) + { + return obj.GetValue(BaseColorProperty); + } + + public static void SetBaseColor(AvaloniaObject obj, Color value) + { + obj.SetValue(BaseColorProperty, value); + } + + public static HslDiff GetHue(AvaloniaObject obj) + { + return obj.GetValue(HueProperty); + } + + public static void SetHue(AvaloniaObject obj, HslDiff value) + { + obj.SetValue(HueProperty, value); + } } \ No newline at end of file diff --git a/AvaloniaStyles/Controls/AlternativeScrollViewer.cs b/AvaloniaStyles/Controls/AlternativeScrollViewer.cs deleted file mode 100644 index 80c164723..000000000 --- a/AvaloniaStyles/Controls/AlternativeScrollViewer.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Presenters; -using Avalonia.Input; - -namespace AvaloniaStyles.Controls -{ - public class AlternativeScrollViewer : ScrollViewer - { - private bool shouldHandleWheelEvent; - public static readonly DirectProperty ShouldHandleWheelEventProperty = AvaloniaProperty.RegisterDirect("ShouldHandleWheelEvent", o => o.ShouldHandleWheelEvent, (o, v) => o.ShouldHandleWheelEvent = v); - - public bool ShouldHandleWheelEvent - { - get => shouldHandleWheelEvent; - set => SetAndRaise(ShouldHandleWheelEventProperty, ref shouldHandleWheelEvent, value); - } - } - - public class AlternativeScrollContentPresenter : ScrollContentPresenter - { - private bool shouldHandleWheelEvent; - public static readonly DirectProperty ShouldHandleWheelEventProperty = AvaloniaProperty.RegisterDirect("ShouldHandleWheelEvent", o => o.ShouldHandleWheelEvent, (o, v) => o.ShouldHandleWheelEvent = v); - - public bool ShouldHandleWheelEvent - { - get => shouldHandleWheelEvent; - set => SetAndRaise(ShouldHandleWheelEventProperty, ref shouldHandleWheelEvent, value); - } - - protected override void OnPointerWheelChanged(PointerWheelEventArgs e) - { - base.OnPointerWheelChanged(e); - e.Handled = shouldHandleWheelEvent; - } - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/BaseMessageBoxWindow.cs b/AvaloniaStyles/Controls/BaseMessageBoxWindow.cs index 948aae2a4..365472d50 100644 --- a/AvaloniaStyles/Controls/BaseMessageBoxWindow.cs +++ b/AvaloniaStyles/Controls/BaseMessageBoxWindow.cs @@ -10,8 +10,10 @@ namespace AvaloniaStyles.Controls { - public class BaseMessageBoxWindow : Window, IStyleable + public class BaseMessageBoxWindow : Window { + protected override Type StyleKeyOverride => typeof(BaseMessageBoxWindow); + public static readonly StyledProperty MessageProperty = AvaloniaProperty.Register(nameof(Message)); @@ -30,10 +32,10 @@ public string Header set => SetValue(HeaderProperty, value); } - public static readonly StyledProperty ImageProperty = - AvaloniaProperty.Register(nameof(Image)); + public static readonly StyledProperty ImageProperty = + AvaloniaProperty.Register(nameof(Image)); - public IControl Image + public Control Image { get => GetValue(ImageProperty); set => SetValue(ImageProperty, value); @@ -41,7 +43,6 @@ public IControl Image public BaseMessageBoxWindow() { - this.AttachDevTools(); if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) PseudoClasses.Add(":macos"); else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -49,17 +50,17 @@ public BaseMessageBoxWindow() else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) PseudoClasses.Add(":linux"); - Win32.SetDarkMode(PlatformImpl.Handle.Handle, SystemTheme.EffectiveThemeIsDark); + if (TryGetPlatformHandle() is { } handle) + Win32.SetDarkMode(handle.Handle, SystemTheme.EffectiveThemeIsDark); } - - Type IStyleable.StyleKey => typeof(BaseMessageBoxWindow); protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome; if (Background is ISolidColorBrush brush) - Win32.SetTitleBarColor(PlatformImpl.Handle.Handle, brush.Color); + if (TryGetPlatformHandle() is { } handle) + Win32.SetTitleBarColor(handle.Handle, brush.Color); } } } \ No newline at end of file diff --git a/AvaloniaStyles/Controls/CompletionComboBox.axaml b/AvaloniaStyles/Controls/CompletionComboBox.axaml index 37a339bcf..788c98b89 100644 --- a/AvaloniaStyles/Controls/CompletionComboBox.axaml +++ b/AvaloniaStyles/Controls/CompletionComboBox.axaml @@ -45,8 +45,8 @@ MaxWidth="700" MaxHeight="600" PlacementConstraintAdjustment="SlideY,SlideX" - PlacementMode="Bottom" - PlacementGravity="Bottom" + Placement="BottomEdgeAlignedLeft" + PlacementGravity="BottomLeft" PlacementTarget="PART_Button"> - \ No newline at end of file + diff --git a/AvaloniaStyles/Controls/CompletionComboBox.axaml.cs b/AvaloniaStyles/Controls/CompletionComboBox.axaml.cs index b31b51bfe..161a49d7c 100644 --- a/AvaloniaStyles/Controls/CompletionComboBox.axaml.cs +++ b/AvaloniaStyles/Controls/CompletionComboBox.axaml.cs @@ -230,19 +230,23 @@ private void Copy() if (SelectedItem != null) { if (watermark is not null) - AvaloniaLocator.Current.GetRequiredService().SetTextAsync(watermark); + TopLevel.GetTopLevel(this)?.Clipboard?.SetTextAsync(watermark); } } private async Task Paste() { - var text = await AvaloniaLocator.Current.GetRequiredService().GetTextAsync(); + var textTask = TopLevel.GetTopLevel(this)?.Clipboard?.GetTextAsync(); + if (textTask == null) + return; + var text = await textTask; + //IsDropDownOpen = true; //await Task.Delay(1); - SearchText = text; + SearchText = text ?? ""; SearchTextBox.RaiseEvent(new KeyEventArgs() { - Device = null, + //Device = null, Handled = false, Key = Key.Enter, Route = RoutingStrategies.Tunnel, @@ -260,15 +264,13 @@ protected override void OnTextInput(TextInputEventArgs e) IsDropDownOpen = true; DispatcherTimer.RunOnce(() => { - SearchTextBox.RaiseEvent(new TextInputEventArgs - { - Device = e.Device, - Handled = false, - Text = e.Text, - Route = e.Route, - RoutedEvent = e.RoutedEvent, - Source = SearchTextBox - }); + TextInputEventArgs args = new TextInputEventArgs(); + args.Handled = false; + args.Text = e.Text; + args.Route = e.Route; + args.RoutedEvent = e.RoutedEvent; + args.Source = SearchTextBox; + SearchTextBox.RaiseEvent(args); }, TimeSpan.FromMilliseconds(1)); e.Handled = true; } @@ -302,7 +304,7 @@ static CompletionComboBox() return; //box.SearchText = ""; - FocusManager.Instance!.Focus(box.SearchTextBox, NavigationMethod.Pointer); + box.SearchTextBox.Focus(NavigationMethod.Pointer); box.SearchTextBox.SelectionEnd = box.SearchTextBox.SelectionStart = box.SearchText.Length; }, TimeSpan.FromMilliseconds(16)); @@ -318,12 +320,12 @@ static CompletionComboBox() protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { - SearchTextBox = e.NameScope.Find("PART_SearchTextBox"); + SearchTextBox = e.NameScope.Find("PART_SearchTextBox") ?? throw new NullReferenceException("Couldn't find PART_SearchTextBox"); SearchTextBox.AddHandler(KeyDownEvent, SearchTextBoxOnKeyDown, RoutingStrategies.Tunnel); - ToggleButton = e.NameScope.Find("PART_Button"); + ToggleButton = e.NameScope.Find("PART_Button") ?? throw new NullReferenceException("Couldn't find PART_Button"); - ListBox = e.NameScope.Find("PART_SelectingItemsControl"); + ListBox = e.NameScope.Find("PART_SelectingItemsControl") ?? throw new NullReferenceException("Couldn't find PART_SelectingItemsControl"); ListBox.PointerReleased += OnSelectorPointerReleased; if (ListBox != null) { @@ -350,11 +352,11 @@ private void SearchTextBoxOnKeyDown(object? sender, KeyEventArgs e) return; if (watermark == null) return; - foreach (var binding in AvaloniaLocator.Current.GetRequiredService().Copy) + foreach (var binding in TopLevel.GetTopLevel(this)!.PlatformSettings!.HotkeyConfiguration!.Copy) { if (binding.Matches(e)) { - AvaloniaLocator.Current.GetRequiredService().SetTextAsync(watermark); + TopLevel.GetTopLevel(this)?.Clipboard?.SetTextAsync(watermark); e.Handled = true; } } @@ -362,7 +364,7 @@ private void SearchTextBoxOnKeyDown(object? sender, KeyEventArgs e) private void OnSelectorPointerReleased(object? sender, PointerReleasedEventArgs e) { - if (e.Source is IControl control && control.FindAncestorOfType() != null) + if (e.Source is Control control && control.FindAncestorOfType() != null) return; Commit(adapter?.SelectedItem); @@ -374,7 +376,7 @@ private void OnTextBoxTextChanged() Dispatcher.UIThread.Post(() => { // Call the central updated text method as a user-initiated action - TextUpdated(textBox.Text); + TextUpdated(textBox.Text ?? ""); }); } @@ -396,14 +398,14 @@ protected ISelectionAdapter SelectionAdapter { if (adapter != null) { - adapter.Items = null; + adapter.ItemsSource = null; } adapter = value; if (adapter != null) { - adapter.Items = view; + adapter.ItemsSource = view; } } } @@ -427,6 +429,23 @@ private TextBox SearchTextBox textBox.GetObservable(TextBox.TextProperty) .Skip(1) .Subscribe(_ => OnTextBoxTextChanged()) + .Combine( + textBox.AddDisposableHandler(TextInputEvent, (_, args) => + { + if (args.Text == " ") + { + if (SelectionAdapter.SelectedItem != null) + { + var container = + ListBox.ContainerFromIndex(ListBox.SelectedIndex); + if (container?.FindDescendantOfType() is CheckBox cb) + { + cb.IsChecked = !cb.IsChecked; + args.Handled = true; + } + } + } + }, RoutingStrategies.Tunnel)) .Combine( textBox.AddDisposableHandler(KeyDownEvent, (_, args) => { @@ -435,7 +454,7 @@ private TextBox SearchTextBox if (args.Key == Key.Enter) { - var enterArgs = new EnterPressedArgs(textBox.Text, + var enterArgs = new EnterPressedArgs(textBox.Text ?? "", SelectionAdapter.SelectedItem); OnEnterPressed?.Invoke(this, enterArgs); if (!enterArgs.Handled) @@ -445,8 +464,15 @@ private TextBox SearchTextBox } else if (args.Key == Key.Tab) { - args.Key = (args.KeyModifiers & KeyModifiers.Shift) != 0 ? Key.Up : Key.Down; - SelectionAdapter.HandleKeyDown(args); + var newArgs = new KeyEventArgs() + { + Key = (args.KeyModifiers & KeyModifiers.Shift) != 0 ? Key.Up : Key.Down, + Route = args.Route, + RoutedEvent = args.RoutedEvent, + KeyModifiers = args.KeyModifiers, + Source = args.Source, + }; + SelectionAdapter.HandleKeyDown(newArgs); args.Handled = true; } else if (args.Key == Key.Escape) @@ -454,20 +480,6 @@ private TextBox SearchTextBox Close(); args.Handled = true; } - else if (args.Key == Key.Space) - { - if (SelectionAdapter.SelectedItem != null) - { - var container = - ListBox.ItemContainerGenerator - .ContainerFromIndex(ListBox.SelectedIndex); - if (container?.FindDescendantOfType() is CheckBox cb) - { - cb.IsChecked = !cb.IsChecked; - args.Handled = true; - } - } - } else { SelectionAdapter.HandleKeyDown(args); @@ -478,7 +490,7 @@ private TextBox SearchTextBox // don't ever let textbox lost focus if (IsDropDownOpen) { - Dispatcher.UIThread.Post(() => FocusManager.Instance!.Focus(textBox)); + Dispatcher.UIThread.Post(() => textBox.Focus()); } })); } @@ -498,7 +510,7 @@ private void Commit(object? item) private void Close() { IsDropDownOpen = false; - FocusManager.Instance!.Focus(ToggleButton, NavigationMethod.Tab); + ToggleButton.Focus(NavigationMethod.Tab); Closed?.Invoke(); } @@ -542,7 +554,12 @@ private async Task PopulateAsync(string searchText, CancellationToken cancellati { try { - IEnumerable result = await asyncPopulator.Invoke(items ?? Array.Empty(), searchText, cancellationToken); + IEnumerable? result = await asyncPopulator.Invoke(items ?? Array.Empty(), searchText, cancellationToken); + if (result == null) + { + view.Clear(); + return; + } var resultList = result is IList ? (IList)result : result.Cast()?.ToList(); if (cancellationToken.IsCancellationRequested) @@ -567,4 +584,4 @@ await Dispatcher.UIThread.InvokeAsync(() => } } } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/ControlRenderer.cs b/AvaloniaStyles/Controls/ControlRenderer.cs new file mode 100644 index 000000000..e7c084d31 --- /dev/null +++ b/AvaloniaStyles/Controls/ControlRenderer.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Threading; + +namespace AvaloniaStyles.Controls; + +public class ControlRenderer : Control +{ + public Action? RenderOverride { get; set; } + + public override void Render(DrawingContext context) + { + RenderOverride?.Invoke(context); + } +} + +public abstract class RenderedPanel : Panel +{ + private ControlRenderer renderer; + + public Control Renderer => renderer; + + public RenderedPanel() + { + renderer = new ControlRenderer(); + Children.Add(renderer); + renderer.RenderOverride = Render; + + Children.CollectionChanged += (sender, args) => + { + if (args.Action == NotifyCollectionChangedAction.Reset) + { + Children.Add(renderer); + } + else if (args.Action == NotifyCollectionChangedAction.Remove && + ReferenceEquals(args.OldItems![0], renderer)) + { + Children.Add(renderer); + } + }; + } + + protected void EnsureRenderer() + { + if (!Children.Contains(renderer)) + Children.Add(renderer); + } + + public IEnumerable ActualChildren => Children.Where(x => !IsRenderer(x)); + + public IEnumerable ActualVisualChildren => VisualChildren.Where(x => !IsRenderer(x)); + + // might be not the best solution? + protected override void ArrangeCore(Rect finalRect) + { + base.ArrangeCore(finalRect); + renderer.Arrange(new Rect(0, 0, finalRect.Width, finalRect.Height)); + } + + protected bool IsRenderer(Control control) + { + return ReferenceEquals(control, renderer); + } + + protected bool IsRenderer(Visual visual) + { + return ReferenceEquals(visual, renderer); + } + + protected static void AffectsRender(AvaloniaProperty property) where T : RenderedPanel + { + property.Changed.AddClassHandler((t, e) => + { + t.InvalidateVisual(); + }); + } + + public new void InvalidateVisual() + { + renderer.InvalidateVisual(); + } + + public new abstract void Render(DrawingContext context); +} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/DismissPopupBehaviour.cs b/AvaloniaStyles/Controls/DismissPopupBehaviour.cs index f3e7fb57f..ca23dda6f 100644 --- a/AvaloniaStyles/Controls/DismissPopupBehaviour.cs +++ b/AvaloniaStyles/Controls/DismissPopupBehaviour.cs @@ -22,7 +22,7 @@ protected override void OnDetaching() private void Handler(object? sender, PointerReleasedEventArgs e) { var control = (sender as Control); - var popup = control.FindLogicalAncestorOfType(); + var popup = control?.FindLogicalAncestorOfType(); if (popup != null) popup.IsOpen = false; } diff --git a/AvaloniaStyles/Controls/DropDownButton.axaml b/AvaloniaStyles/Controls/DropDownButton.axaml deleted file mode 100644 index dea1106fd..000000000 --- a/AvaloniaStyles/Controls/DropDownButton.axaml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - diff --git a/AvaloniaStyles/Controls/DropDownButton.axaml.cs b/AvaloniaStyles/Controls/DropDownButton.axaml.cs deleted file mode 100644 index a74256f4c..000000000 --- a/AvaloniaStyles/Controls/DropDownButton.axaml.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Metadata; - -namespace AvaloniaStyles.Controls -{ - public class DropDownButton : TemplatedControl - { - private object? button; - public static readonly DirectProperty ButtonProperty = AvaloniaProperty.RegisterDirect("Button", o => o.Button, (o, v) => o.Button = v); - private bool isDropDownOpened; - public static readonly DirectProperty IsDropDownOpenedProperty = AvaloniaProperty.RegisterDirect("IsDropDownOpened", o => o.IsDropDownOpened, (o, v) => o.IsDropDownOpened = v); - - public static readonly StyledProperty ChildProperty = - AvaloniaProperty.Register(nameof(Child)); - - public object? Button - { - get => button; - set => SetAndRaise(ButtonProperty, ref button, value); - } - - public bool IsDropDownOpened - { - get => isDropDownOpened; - set => SetAndRaise(IsDropDownOpenedProperty, ref isDropDownOpened, value); - } - - [Content] - public Control? Child - { - get => GetValue(ChildProperty); - set => SetValue(ChildProperty, value); - } - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/ExtendedWindow.cs b/AvaloniaStyles/Controls/ExtendedWindow.cs index 11c41dec3..f9ba12a6f 100644 --- a/AvaloniaStyles/Controls/ExtendedWindow.cs +++ b/AvaloniaStyles/Controls/ExtendedWindow.cs @@ -10,12 +10,11 @@ using Avalonia.Platform; using Avalonia.Styling; using Avalonia.Threading; -using Avalonia.Win32; using AvaloniaStyles.Utils; namespace AvaloniaStyles.Controls { - public class ExtendedWindow : Window, IStyleable + public class ExtendedWindow : Window { public static readonly StyledProperty ManagedIconProperty = AvaloniaProperty.Register(nameof(ManagedIcon)); @@ -26,8 +25,8 @@ public class ExtendedWindow : Window, IStyleable public static readonly StyledProperty ToolBarProperty = AvaloniaProperty.Register(nameof(ToolBar)); - public static readonly StyledProperty SideBarProperty = - AvaloniaProperty.Register(nameof(SideBar)); + public static readonly StyledProperty SideBarProperty = + AvaloniaProperty.Register(nameof(SideBar)); public static readonly StyledProperty StatusBarProperty = AvaloniaProperty.Register(nameof(StatusBar)); @@ -35,8 +34,8 @@ public class ExtendedWindow : Window, IStyleable public static readonly StyledProperty TabStripProperty = AvaloniaProperty.Register(nameof(TabStrip)); - public static readonly StyledProperty OverlayProperty = - AvaloniaProperty.Register(nameof(Overlay)); + public static readonly StyledProperty OverlayProperty = + AvaloniaProperty.Register(nameof(Overlay)); public static readonly StyledProperty SubTitleProperty = AvaloniaProperty.Register(nameof(SubTitle)); @@ -59,7 +58,7 @@ public ToolBar ToolBar set => SetValue(ToolBarProperty, value); } - public IControl? SideBar + public Control? SideBar { get => GetValue(SideBarProperty); set => SetValue(SideBarProperty, value); @@ -71,7 +70,7 @@ public StatusBar StatusBar set => SetValue(StatusBarProperty, value); } - public IControl Overlay + public Control Overlay { get => GetValue(OverlayProperty); set => SetValue(OverlayProperty, value); @@ -89,7 +88,7 @@ public TabStrip TabStrip set => SetValue(TabStripProperty, value); } - Type IStyleable.StyleKey => typeof(ExtendedWindow); + protected override Type StyleKeyOverride => typeof(ExtendedWindow); static ExtendedWindow() { @@ -121,38 +120,34 @@ static ExtendedWindow() BackgroundProperty.Changed.AddClassHandler((window, e) => { - window.BindBackgroundBrush(e.NewValue as Brush); + window.BindBackgroundBrush(e.NewValue as SolidColorBrush); }); } - private Brush? _backgroundBrush; + private IDisposable? backgroundBrushBinding; private void UnbindBackgroundBrush() { - if (_backgroundBrush != null) - { - _backgroundBrush.Invalidated -= BackgroundBrushOnInvalidated; - _backgroundBrush = null; - } + backgroundBrushBinding?.Dispose(); + backgroundBrushBinding = null; } - private void BindBackgroundBrush(Brush? brush) + private void BindBackgroundBrush(SolidColorBrush? brush) { UnbindBackgroundBrush(); - - _backgroundBrush = brush; - + if (brush != null) { - brush.Invalidated += BackgroundBrushOnInvalidated; - BackgroundBrushOnInvalidated(null, EventArgs.Empty); + backgroundBrushBinding = brush.GetObservable(SolidColorBrush.ColorProperty) + .Subscribe(_ => BackgroundBrushOnInvalidated(null, EventArgs.Empty)); } } private void BackgroundBrushOnInvalidated(object? sender, EventArgs e) { - if (Background is ISolidColorBrush brush && PlatformImpl != null) - Win32.SetTitleBarColor(PlatformImpl.Handle.Handle, brush.Color); + if (Background is ISolidColorBrush brush) + if (TryGetPlatformHandle() is { } handle) + Win32.SetTitleBarColor(handle.Handle, brush.Color); } private void UpdateChromeHints(ExtendedWindowChrome chrome) @@ -178,7 +173,8 @@ public ExtendedWindow() PseudoClasses.Add(":macos"); else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - Win32.SetDarkMode(PlatformImpl.Handle.Handle, SystemTheme.EffectiveThemeIsDark); + if (TryGetPlatformHandle() is { } handle) + Win32.SetDarkMode(handle.Handle, SystemTheme.EffectiveThemeIsDark); PseudoClasses.Add(":windows"); if (Environment.OSVersion.Version.Build >= 22000) PseudoClasses.Add(":win11"); @@ -194,12 +190,14 @@ private static void UpdateScaling(Window window) if (!SystemTheme.CustomScalingValue.HasValue) { var primaryScreen = window.Screens.Primary ?? window.Screens.All.FirstOrDefault(); - scaling = (primaryScreen?.PixelDensity ?? 1); + scaling = (primaryScreen?.Scaling ?? 1); } else scaling = SystemTheme.CustomScalingValue.Value; var impl = window.PlatformImpl; + if (impl == null) + return; var f = impl.GetType().GetField("_scaling", BindingFlags.Instance | BindingFlags.NonPublic); if (f != null) { @@ -209,7 +207,8 @@ private static void UpdateScaling(Window window) var oldWidth = window.Width * curVal; var oldHeight = window.Height * curVal; f.SetValue(impl, scaling); - impl.ScalingChanged(scaling); + Action? scalingChanged = (Action?)impl.GetType().GetProperty("ScalingChanged", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)?.GetValue(impl); + scalingChanged?.Invoke(scaling); DispatcherTimer.RunOnce(() => { window.Width = oldWidth / scaling; @@ -288,4 +287,4 @@ public enum ExtendedWindowChrome AlwaysSystemChrome, MacOsChrome } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/Extensions.cs b/AvaloniaStyles/Controls/Extensions.cs index 5048c0310..177188f1a 100644 --- a/AvaloniaStyles/Controls/Extensions.cs +++ b/AvaloniaStyles/Controls/Extensions.cs @@ -13,7 +13,7 @@ using Avalonia.Layout; using AvaloniaStyles.Converters; using FuzzySharp; -using JetBrains.Annotations; +using WDE.MVVM; using WDE.MVVM.Observable; namespace AvaloniaStyles.Controls @@ -22,13 +22,13 @@ internal class EnumToIntConverter : IValueConverter { public static EnumToIntConverter Instance { get; } = new(); - public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { var val = System.Convert.ToUInt32(value); return $"{value} ({val})"; } - public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { throw new NotImplementedException(); } @@ -56,11 +56,10 @@ private static bool IsFlagEnum(Type type) return type.GetCustomAttribute() != null; } - internal sealed class Option : INotifyPropertyChanged + internal sealed class Option : ObservableBase, INotifyPropertyChanged { private readonly Type type; private readonly WeakReference completionBoxReference; - private IDisposable? disposable; public Option(object enumValue, Type type, CompletionComboBox combo, string text) { @@ -71,7 +70,6 @@ public Option(object enumValue, Type type, CompletionComboBox combo, string text EnumInteger = Convert.ToUInt32(enumValue); TextWithNumber = $"{Text} {EnumInteger}"; - subscribed = 0; } public string TextWithNumber { get; } @@ -112,48 +110,15 @@ public bool IsChecked } } - private event PropertyChangedEventHandler? PropertyChanged; - - private int subscribed; - event PropertyChangedEventHandler? INotifyPropertyChanged.PropertyChanged { - add - { - if (!completionBoxReference.TryGetTarget(out var completionBox)) - return; - - subscribed++; - PropertyChanged += value; - if (subscribed > 0) - { - if (disposable != null) - throw new Exception(); - disposable = completionBox.GetObservable(CompletionComboBox.SelectedItemProperty).SubscribeAction(_ => - { - OnPropertyChanged(nameof(IsChecked)); - }); - } - } - remove - { - if (!completionBoxReference.TryGetTarget(out _)) - return; - - PropertyChanged -= value; - subscribed--; - if (subscribed == 0) - { - disposable?.Dispose(); - disposable = null; - } - } + add => PropertyChanged += value; + remove => PropertyChanged -= value; } - [NotifyPropertyChangedInvocator] - private void OnPropertyChanged([CallerMemberName] string? propertyName = null) + public void RaiseIsChecked(CompletionComboBox combo) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + RaisePropertyChanged(nameof(IsChecked)); } } @@ -165,6 +130,11 @@ static Extensions() return; var values = Enum.GetValuesAsUnderlyingType(type).Cast().Zip(Enum.GetNames(type), (val, name) => new Option(val, type, combo, name)).ToList(); + combo.GetObservable(CompletionComboBox.SelectedItemProperty).SubscribeAction(_ => + { + foreach (var val in values) + val.RaiseIsChecked(combo); + }); combo.AsyncPopulator = async (items, str, _) => { if (string.IsNullOrEmpty(str)) @@ -232,4 +202,4 @@ static Extensions() }); } } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/FastTableView/ColorsDark.axaml b/AvaloniaStyles/Controls/FastTableView/ColorsDark.axaml index 5930a1d54..219e2d786 100644 --- a/AvaloniaStyles/Controls/FastTableView/ColorsDark.axaml +++ b/AvaloniaStyles/Controls/FastTableView/ColorsDark.axaml @@ -2,14 +2,14 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + - + diff --git a/AvaloniaStyles/Controls/FastTableView/ColorsLight.axaml b/AvaloniaStyles/Controls/FastTableView/ColorsLight.axaml index e46ffca0e..df33bd30c 100644 --- a/AvaloniaStyles/Controls/FastTableView/ColorsLight.axaml +++ b/AvaloniaStyles/Controls/FastTableView/ColorsLight.axaml @@ -2,14 +2,14 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> - + - + diff --git a/AvaloniaStyles/Controls/FastTableView/Extensions.cs b/AvaloniaStyles/Controls/FastTableView/Extensions.cs index 128712cc8..57e188e57 100644 --- a/AvaloniaStyles/Controls/FastTableView/Extensions.cs +++ b/AvaloniaStyles/Controls/FastTableView/Extensions.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Styling; namespace AvaloniaStyles.Controls.FastTableView; @@ -7,12 +8,12 @@ internal static partial class Extensions public static bool GetResource(this object? _, string key, T defaultVal, out T outT) { outT = defaultVal; - if ((Application.Current?.Styles.TryGetResource(key, out var res) ?? false) && res is T t) + if ((Application.Current?.Styles.TryGetResource(key, SystemTheme.EffectiveThemeVariant, out var res) ?? false) && res is T t) { outT = t; return true; } - if ((Application.Current?.Resources.TryGetResource(key, out var res2) ?? false) && res2 is T t2) + if ((Application.Current?.Resources.TryGetResource(key, SystemTheme.EffectiveThemeVariant, out var res2) ?? false) && res2 is T t2) { outT = t2; return true; diff --git a/AvaloniaStyles/Controls/FastTableView/ICustomCellDrawer.cs b/AvaloniaStyles/Controls/FastTableView/ICustomCellDrawer.cs index f3cbac767..ae903abe6 100644 --- a/AvaloniaStyles/Controls/FastTableView/ICustomCellDrawer.cs +++ b/AvaloniaStyles/Controls/FastTableView/ICustomCellDrawer.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Threading.Tasks; using Avalonia; using Avalonia.Media; @@ -190,15 +191,13 @@ public bool UpdateCursor(Point point, bool leftPressed) protected void DrawText(DrawingContext context, Rect rect, string text, Color? color = null, float opacity = 0.4f) { - var ft = new FormattedText + var textColor = new SolidColorBrush(color ?? TextBrush.Color, opacity); + var ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(MonoFont), 12, textColor) { - Text = text, - Constraint = new Size(rect.Width, rect.Height), - Typeface = new Typeface(MonoFont),//Typeface.Default, - FontSize = 12 + MaxTextHeight = rect.Height, + MaxTextWidth = float.MaxValue // rect.Width // we don't want text wrapping so pass float.MaxValue }; - var textColor = new SolidColorBrush(color ?? TextBrush.Color, opacity); - context.DrawText(textColor, new Point(rect.X, rect.Center.Y - ft.Bounds.Height / 2), ft); + context.DrawText(ft, new Point(rect.X, rect.Center.Y - ft.Height / 2)); } private const double CheckBoxSize = 20; @@ -261,28 +260,18 @@ protected void DrawButton(DrawingContext context, Rect rect, string text, int ma var state = context.PushClip(rect); if (char.IsAscii(text[0])) { - var ft = new FormattedText + var ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, Typeface.Default, 12, ButtonTextPen.Brush) { - Text = text, - Constraint = new Size(rect.Width, rect.Height), - Typeface = Typeface.Default, - FontSize = 12 + MaxTextHeight = rect.Height, + MaxTextWidth = float.MaxValue // rect.Width // we don't want text wrapping so pass float.MaxValue }; - context.DrawText(ButtonTextPen.Brush, new Point(rect.Center.X - ft.Bounds.Width / 2, rect.Center.Y - ft.Bounds.Height / 2), ft); + context.DrawText(ft, new Point(rect.Center.X - ft.Width / 2, rect.Center.Y - ft.Height / 2)); } else { var tl = new TextLayout(text, Typeface.Default, 12, ButtonTextPen.Brush, TextAlignment.Center, maxWidth: rect.Width, maxHeight:rect.Height); - Draw(tl, context, new Point(rect.Left, rect.Center.Y - tl.Size.Height / 2)); + tl.Draw(context, new Point(rect.Left, rect.Center.Y - tl.Height / 2)); } state.Dispose(); } - - /* not required in avalonia 11, just call layout.Draw(context, p) */ - private static void Draw(TextLayout layout, DrawingContext context, Point p) - { - double offset = layout.MaxWidth / 2 - layout.Size.Width / 2; - using var _ = context.PushPostTransform(Matrix.CreateTranslation(p.X + offset, p.Y)); - layout.Draw(context); - } } \ No newline at end of file diff --git a/AvaloniaStyles/Controls/FastTableView/PhantomTextBox.cs b/AvaloniaStyles/Controls/FastTableView/PhantomTextBox.cs index 94c1186f5..cb711c8f5 100644 --- a/AvaloniaStyles/Controls/FastTableView/PhantomTextBox.cs +++ b/AvaloniaStyles/Controls/FastTableView/PhantomTextBox.cs @@ -19,7 +19,6 @@ namespace AvaloniaStyles.Controls.FastTableView; public abstract class PhantomControlBase where T : Control { private AdornerLayer? adornerLayer = null; - private Panel panel = null!; private Visual? parent = null!; private IDisposable? clickDisposable = null; private IDisposable? focusDisposable = null; @@ -102,7 +101,7 @@ protected void Despawn(bool save) focusDisposable = null; if (parent is IInputElement inputElement) - FocusManager.Instance!.Focus(inputElement); + inputElement.Focus(); element = null; parent = null; IsOpened = false; @@ -122,7 +121,7 @@ public enum ActionAfterSave private Action? currentOnApply = null; private ActionAfterSave actionAfterSave; - public void Spawn(Visual parent, Rect position, string text, bool selectAll, Action onApply, FontFamily? customFont = null) + public void Spawn(Visual parent, Rect position, string text, bool selectAll, Action onApply) { Despawn(false); @@ -135,7 +134,7 @@ public void Spawn(Visual parent, Rect position, string text, bool selectAll, Act textBox.Padding = new Thickness(5 + 3, -2, 0, 0); textBox.Margin = new Thickness(0, 0, 0, 0); textBox.Text = text; - textBox.FontFamily = customFont ?? new FontFamily("Consolas,Menlo,Courier,Courier New"); + textBox.FontFamily = new FontFamily("Consolas,Menlo,Courier,Courier New"); textBox.KeyBindings.Add(new KeyBinding() { Gesture = new KeyGesture(Key.Enter), @@ -181,8 +180,8 @@ public void Spawn(Visual parent, Rect position, string text, bool selectAll, Act return; textBox.LostFocus += ElementLostFocus; - - DispatcherTimer.RunOnce(textBox.Focus, TimeSpan.FromMilliseconds(1)); + + DispatcherTimer.RunOnce(() => textBox.Focus(), TimeSpan.FromMilliseconds(1)); if (selectAll) textBox.SelectAll(); else @@ -203,7 +202,7 @@ protected override void Cleanup(TextBox element) protected override void Save(TextBox element) { - currentOnApply?.Invoke(element.Text, actionAfterSave); + currentOnApply?.Invoke(element.Text ?? "", actionAfterSave); } } @@ -240,7 +239,7 @@ protected void Spawn(Visual parent, Rect position, string? searchText, IEnumerab flagsComboBox.IsLightDismissEnabled = false; // we are handling it ourselves, without doing .Handled = true so that as soon as user press outside of popup, the click is treated as actual click flagsComboBox.Closed += CompletionComboBoxOnClosed; - if (!AttachAsAdorner(parent, position, flagsComboBox)) + if (!AttachAsAdorner(parent, position, flagsComboBox, true)) return; DispatcherTimer.RunOnce(() => @@ -259,4 +258,4 @@ protected override void Cleanup(CompletionComboBox element) { element.Closed -= CompletionComboBoxOnClosed; } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/FastTableView/Row.cs b/AvaloniaStyles/Controls/FastTableView/Row.cs index dab9cc28d..3062ef0dc 100644 --- a/AvaloniaStyles/Controls/FastTableView/Row.cs +++ b/AvaloniaStyles/Controls/FastTableView/Row.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; using System.Linq; using System.Runtime.CompilerServices; -using JetBrains.Annotations; namespace AvaloniaStyles.Controls.FastTableView; @@ -86,7 +84,6 @@ public void UpdateFromString(string newValue) public string? StringValue => value.ToString(); - [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Arrange.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Arrange.cs index d233f93ea..164214834 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Arrange.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Arrange.cs @@ -28,7 +28,7 @@ protected override Size ArrangeOverride(Size finalSize) } headerViews.Reset(template); - subheaderViews.Reset(AdditionalGroupSubHeaderTemplate); + subheaderViews.Reset(AdditionalGroupSubHeader); if (!IsGroupingEnabled) { diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Data.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Data.cs index 64149458c..ccbcffe61 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Data.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Data.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using Avalonia.Threading; using DynamicData; using WDE.Common.Utils; @@ -61,18 +62,18 @@ private void FixSelectedRowIndexIfInvalid() return; if (Items == null) { - SelectedRowIndex = VerticalCursor.None; + SetCurrentValue(SelectedRowIndexProperty, VerticalCursor.None); return; } if (SelectedRowIndex.GroupIndex >= Items.Count) { - SelectedRowIndex = VerticalCursor.None; + SetCurrentValue(SelectedRowIndexProperty, VerticalCursor.None); return; } if (SelectedRowIndex.RowIndex >= Items[SelectedRowIndex.GroupIndex].Rows.Count) - SelectedRowIndex = VerticalCursor.None; + SetCurrentValue(SelectedRowIndexProperty, VerticalCursor.None); } private void ItemsChanged(object? sender, NotifyCollectionChangedEventArgs e) @@ -111,7 +112,9 @@ private void RowChanged(ITableRowGroup group, ITableRow obj) var rowIndex = Items[groupIndex].Rows.IndexOf(obj); if (IsRowVisible(new VerticalCursor(groupIndex, rowIndex))) - InvalidateVisual(); + { + Dispatcher.UIThread.Post(InvalidateVisual); + } } diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Navigation.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Navigation.cs index 5314487b4..a7326ccf6 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Navigation.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Navigation.cs @@ -39,10 +39,10 @@ private bool MoveCursorRight() if (TableSpan is { } span && span.IsMerged(SelectedRowIndex.GroupIndex, SelectedRowIndex.RowIndex, next.Value, out var firstRow, out var firstColumn)) { next = firstColumn; - SelectedRowIndex = new VerticalCursor(SelectedRowIndex.GroupIndex, firstRow); + SetCurrentValue(SelectedRowIndexProperty, new VerticalCursor(SelectedRowIndex.GroupIndex, firstRow)); } - SelectedCellIndex = next.Value; + SetCurrentValue(SelectedCellIndexProperty, next.Value); return true; } @@ -55,10 +55,10 @@ private bool MoveCursorLeft() if (TableSpan is { } span && span.IsMerged(SelectedRowIndex.GroupIndex, SelectedRowIndex.RowIndex, prev.Value, out var firstRow, out var firstColumn)) { prev = firstColumn; - SelectedRowIndex = new VerticalCursor(SelectedRowIndex.GroupIndex, firstRow); + SetCurrentValue(SelectedRowIndexProperty, new VerticalCursor(SelectedRowIndex.GroupIndex, firstRow)); } - SelectedCellIndex = prev.Value; + SetCurrentValue(SelectedCellIndexProperty, prev.Value); return true; } @@ -118,7 +118,7 @@ int FixRowToFirstMerged(int group, int row) { if (IsFilteredRowVisible(items[group], items[group].Rows[row], rowFilter, rowFilterParameter)) { - SelectedRowIndex = new VerticalCursor(group, row); + SetCurrentValue(SelectedRowIndexProperty, new VerticalCursor(group, row)); return true; } } @@ -148,7 +148,7 @@ private bool MoveCursorPrevious() if (MoveCursorLeft()) return true; - SelectedCellIndex = ColumnsCount - 1; + SetCurrentValue(SelectedCellIndexProperty, ColumnsCount - 1); return MoveCursorUp(); } @@ -156,16 +156,10 @@ private bool MoveCursorNext() { if (MoveCursorRight()) return true; - SelectedCellIndex = 0; + SetCurrentValue(SelectedCellIndexProperty, 0); return MoveCursorDown(); } - - public void SetOwner(IInputRoot owner) - { - - } - public void Move(IInputElement element, NavigationDirection direction, KeyModifiers keyModifiers = KeyModifiers.None) { switch (direction) @@ -177,12 +171,12 @@ public void Move(IInputElement element, NavigationDirection direction, KeyModifi MoveCursorPrevious(); break; case NavigationDirection.First: - SelectedRowIndex = new VerticalCursor(0, 0); - SelectedCellIndex = 0; + SetCurrentValue(SelectedRowIndexProperty, new VerticalCursor(0, 0)); + SetCurrentValue(SelectedCellIndexProperty, 0); break; case NavigationDirection.Last: - SelectedRowIndex = new VerticalCursor(Items?.Count ?? 0 - 1, Items?[^1]?.Rows?.Count ?? 0 - 1); - SelectedCellIndex = ColumnsCount - 1; + SetCurrentValue(SelectedRowIndexProperty, new VerticalCursor(Items?.Count ?? 0 - 1, Items?[^1]?.Rows?.Count ?? 0 - 1)); + SetCurrentValue(SelectedCellIndexProperty, ColumnsCount - 1); break; case NavigationDirection.Left: MoveCursorLeft(); diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Properties.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Properties.cs index 653832e2e..d911d69b2 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Properties.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Properties.cs @@ -30,20 +30,20 @@ public partial class VeryFastTableView public static readonly StyledProperty CustomCellInteractorProperty = AvaloniaProperty.Register(nameof(CustomCellInteractor)); public static readonly StyledProperty MultiSelectionProperty = AvaloniaProperty.Register(nameof(MultiSelection), defaultValue: new TableMultiSelection()); public static readonly StyledProperty GroupHeaderTemplateProperty = AvaloniaProperty.Register(nameof(GroupHeaderTemplate)); - public static readonly StyledProperty AdditionalGroupSubHeaderProperty = AvaloniaProperty.Register(nameof(AdditionalGroupSubHeaderTemplate)); + public static readonly StyledProperty AdditionalGroupSubHeaderProperty = AvaloniaProperty.Register(nameof(AdditionalGroupSubHeader)); public static readonly StyledProperty InteractiveHeaderProperty = AvaloniaProperty.Register(nameof(InteractiveHeader)); - public static readonly StyledProperty RowFilterParameterProperty = AvaloniaProperty.Register("RowFilterParameter"); - public static readonly StyledProperty IsGroupingEnabledProperty = AvaloniaProperty.Register("IsGroupingEnabled"); + public static readonly StyledProperty RowFilterParameterProperty = AvaloniaProperty.Register(nameof(RowFilterParameter)); + public static readonly StyledProperty IsGroupingEnabledProperty = AvaloniaProperty.Register(nameof(IsGroupingEnabled)); public static readonly StyledProperty SubHeaderHeightProperty = AvaloniaProperty.Register(nameof(SubHeaderHeight), defaultValue: 0); - public static readonly StyledProperty IsDynamicHeaderHeightProperty = AvaloniaProperty.Register("DynamicRowHeight"); + public static readonly StyledProperty IsDynamicHeaderHeightProperty = AvaloniaProperty.Register(nameof(IsDynamicHeaderHeight)); - public static readonly RoutedEvent ColumnPressedEvent = RoutedEvent.Register("ColumnPressed", RoutingStrategies.Tunnel | RoutingStrategies.Bubble); + public static readonly RoutedEvent ColumnPressedEvent = RoutedEvent.Register(nameof(ColumnPressed), RoutingStrategies.Tunnel | RoutingStrategies.Bubble); private List columnVisibility = new List(); - public static readonly StyledProperty RowFilterProperty = AvaloniaProperty.Register("RowFilter"); - public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register("IsReadOnly"); + public static readonly StyledProperty RowFilterProperty = AvaloniaProperty.Register(nameof(RowFilter)); + public static readonly StyledProperty IsReadOnlyProperty = AvaloniaProperty.Register(nameof(IsReadOnly)); public static readonly StyledProperty TableSpanProperty = AvaloniaProperty.Register(nameof(TableSpan)); @@ -120,7 +120,7 @@ public IDataTemplate? GroupHeaderTemplate set => SetValue(GroupHeaderTemplateProperty, value); } - public IDataTemplate? AdditionalGroupSubHeaderTemplate + public IDataTemplate? AdditionalGroupSubHeader { get => GetValue(AdditionalGroupSubHeaderProperty); set => SetValue(AdditionalGroupSubHeaderProperty, value); diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Rendering.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Rendering.cs index bc982d7bf..6726a6312 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Rendering.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.Rendering.cs @@ -1,8 +1,11 @@ using System; +using System.Globalization; using System.Linq; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Documents; using Avalonia.Media; +using Avalonia.Styling; using WDE.Common.Utils; using WDE.MVVM.Observable; @@ -19,7 +22,7 @@ private Rect DataViewport { var scrollViewer = ScrollViewer; if (scrollViewer == null) - return Rect.Empty; + return default; return new Rect(scrollViewer.Offset.X, scrollViewer.Offset.Y + DrawingStartOffsetY, scrollViewer.Viewport.Width, scrollViewer.Viewport.Height - DrawingStartOffsetY); } } @@ -45,11 +48,10 @@ protected bool IsFilteredGroupVisible(ITableRowGroup group, IRowFilterPredicate? public override void Render(DrawingContext context) { - base.Render(context); if (Items == null) return; - var font = new Typeface(TextBlock.GetFontFamily(this)); + var font = new Typeface(TextElement.GetFontFamily(this)); var actualWidth = Bounds.Width; @@ -104,13 +106,13 @@ public override void Render(DrawingContext context) } // out of bounds in the upper part - if (groupStartY + groupHeight < DataViewport.Top) + if (groupStartY + groupHeight < viewPort.Top) { if (group.Rows.Count % 2 == 1) odd = !odd; y += groupHeight; } - else if (groupStartY > DataViewport.Bottom) // below + else if (groupStartY > viewPort.Bottom) // below { break; } @@ -162,7 +164,7 @@ public override void Render(DrawingContext context) // we draw only the visible columns // todo: could be optimized so we don't iterate through all columns when we know we don't need to - if (x + columnWidth > DataViewport.Left && x < DataViewport.Right) + if (x + columnWidth > viewPort.Left && x < viewPort.Right) { var rect = span == null ? new Rect(x, y, columnWidth, RowHeight) : CellRect(cellIndex, new VerticalCursor(groupIndex, rowIndex)); var rectWidth = rect.Width; @@ -177,26 +179,21 @@ public override void Render(DrawingContext context) var indexOfEndOfLine = text.IndexOf('\n'); if (indexOfEndOfLine != -1) text = text.Substring(0, indexOfEndOfLine); - + rect = rect.WithWidth(rect.Width - ColumnSpacing); - var ft = new FormattedText - { - Text = text, - Constraint = new Size(rect.Width, rect.Height), - Typeface = font, - FontSize = 12 - }; + var ft = new FormattedText( + text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, font, 12, textColor); + ft.MaxTextWidth = float.MaxValue; // rect.Width; // we don't want to wrap the text, so pass large width + ft.MaxTextHeight = rect.Height; if (Math.Abs(rectWidth - rect.Width) > 0.01) { state.Dispose(); state = context.PushClip(rect); } - - context.DrawText(textColor, - new Point(rect.X + ColumnSpacing, y + rect.Height / 2 - ft.Bounds.Height / 2), - ft); + context.DrawText(ft, new Point(rect.X + ColumnSpacing, y + rect.Height / 2 - ft.Height / 2)); } } + } finally { @@ -241,7 +238,7 @@ private void RenderHeaders(DrawingContext context) return; FontFamily font = FontFamily.Default; - if (Application.Current!.Styles.TryGetResource("MainFontSans", out var mainFontSans) && mainFontSans is FontFamily mainFontSansFamily) + if (Application.Current!.Styles.TryGetResource("MainFontSans", SystemTheme.EffectiveThemeIsDark ? ThemeVariant.Dark : ThemeVariant.Light, out var mainFontSans) && mainFontSans is FontFamily mainFontSansFamily) font = mainFontSansFamily; var scrollViewer = ScrollViewer; @@ -265,12 +262,11 @@ private void RenderHeaders(DrawingContext context) continue; var column = Columns[i]; - var ft = new FormattedText + var ft = new FormattedText(column.Header, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, + new Typeface(font, FontStyle.Normal, FontWeight.Bold), 12, BorderPen.Brush) { - Text = column.Header, - Constraint = new Size(column.Width, RowHeight), - Typeface = new Typeface(font, FontStyle.Normal, FontWeight.Bold), - FontSize = 12 + MaxTextWidth = float.MaxValue, // column.Width // we don't want text wrapping so pass float.MaxValue + MaxTextHeight = RowHeight }; bool isMouseOverColumn = isMouseOverHeader && lastMouseLocation.X >= x && lastMouseLocation.X < x + column.Width; @@ -278,7 +274,7 @@ private void RenderHeaders(DrawingContext context) context.FillRectangle(lastMouseButtonPressed && !isMouseOverSplitter ? HeaderPressedBackground : HeaderHoverBackground, new Rect(x, y, column.Width, RowHeight)); var state = context.PushClip(new Rect(x + ColumnSpacing, y, Math.Max(0, column.Width - ColumnSpacing * 2), RowHeight)); - context.DrawText(BorderPen.Brush, new Point(x + ColumnSpacing, y + RowHeight / 2 - ft.Bounds.Height / 2), ft); + context.DrawText(ft, new Point(x + ColumnSpacing, y + RowHeight / 2 - ft.Height / 2)); state.Dispose(); x += column.Width; @@ -395,4 +391,4 @@ private bool IsColumnVisible(int index) return null; } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.cs b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.cs index b3a952f7d..35d97105a 100644 --- a/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.cs +++ b/AvaloniaStyles/Controls/FastTableView/VeryFastTableView.cs @@ -5,14 +5,16 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Media; +using Avalonia.Styling; using Avalonia.Threading; using Avalonia.VisualTree; +using AvaloniaStyles.Controls.OptimizedVeryFastTableView; using WDE.Common.Utils; using WDE.MVVM.Observable; namespace AvaloniaStyles.Controls.FastTableView; -public partial class VeryFastTableView : Panel, IKeyboardNavigationHandler, IFastTableContext +public partial class VeryFastTableView : RenderedPanel, IFastTableContext { protected static double ColumnSpacing = 10; protected static double HeaderRowHeight = 36; @@ -36,7 +38,7 @@ public partial class VeryFastTableView : Panel, IKeyboardNavigationHandler, IFas private static bool GetResource(string key, T defaultVal, out T outT) { outT = defaultVal; - if (Application.Current!.Styles.TryGetResource(key, out var res) && res is T t) + if (Application.Current!.Styles.TryGetResource(key, SystemTheme.EffectiveThemeVariant, out var res) && res is T t) { outT = t; return true; @@ -109,10 +111,16 @@ static VeryFastTableView() table.UpdateKeyBindings(); }); } - + private Panel headersViewParent; private Panel subheadersViewParent; + private class NoArrangePanel : Panel + { + protected override Size ArrangeOverride(Size finalSize) => finalSize; + protected override Size MeasureOverride(Size availableSize) => availableSize; + } + public VeryFastTableView() { UpdateKeyBindings(); @@ -123,12 +131,47 @@ public VeryFastTableView() headerViews = new RecyclableViewList(headersViewParent); subheaderViews = new RecyclableViewList(subheadersViewParent); headersViewParent.ClipToBounds = subheadersViewParent.ClipToBounds = true; + var openAndErase = new DelegateCommand(() => + { + if (IsSelectedCellValid) + OpenEditor(""); + }); + KeyBindings.Add(new KeyBinding() + { + Gesture = new KeyGesture(Key.Enter), + Command = new DelegateCommand(() => + { + if (IsSelectedCellValid) + OpenEditor(); + }) + }); + KeyBindings.Add(new KeyBinding() + { + Gesture = new KeyGesture(Key.Back), + Command = openAndErase + }); + KeyBindings.Add(new KeyBinding() + { + Gesture = new KeyGesture(Key.Delete), + Command = openAndErase + }); } - private class NoArrangePanel : Panel + private ScrollViewer? boundScrollViewer; + + public override void ApplyTemplate() { - protected override Size ArrangeOverride(Size finalSize) => finalSize; - protected override Size MeasureOverride(Size availableSize) => availableSize; + base.ApplyTemplate(); + if (boundScrollViewer != null) + boundScrollViewer.ScrollChanged -= ScrollViewerOnScrollChanged; + if (ScrollViewer != null) + ScrollViewer.ScrollChanged += ScrollViewerOnScrollChanged; + boundScrollViewer = ScrollViewer; + } + + private void ScrollViewerOnScrollChanged(object? sender, ScrollChangedEventArgs e) + { + InvalidateVisual(); } private void RemoveInvisibleFromSelection() @@ -251,12 +294,12 @@ protected override void OnTextInput(TextInputEventArgs e) } } - protected override void OnPointerLeave(PointerEventArgs e) + protected override void OnPointerExited(PointerEventArgs e) { - Cursor = Cursor.Default; + SetCurrentValue(CursorProperty, Cursor.Default); lastMouseLocation = new Point(-1, -1); InvalidateVisual(); - base.OnPointerLeave(e); + base.OnPointerExited(e); } protected override void OnPointerMoved(PointerEventArgs e) @@ -266,7 +309,7 @@ protected override void OnPointerMoved(PointerEventArgs e) var point = currentPoint.Position; lastMouseLocation = point; lastMouseButtonPressed = currentPoint.Properties.IsLeftButtonPressed; - Cursor = (currentlyResizedColumn.HasValue || IsPointHeader(point) && IsOverColumnSplitter(lastMouseLocation.X, out _)) ? new Cursor(StandardCursorType.SizeWestEast) : Cursor.Default; + SetCurrentValue(CursorProperty, (currentlyResizedColumn.HasValue || IsPointHeader(point) && IsOverColumnSplitter(lastMouseLocation.X, out _)) ? new Cursor(StandardCursorType.SizeWestEast) : Cursor.Default); if (CustomCellDrawer != null) { @@ -307,7 +350,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) var index = GetRowIndexByY(e.GetPosition(this)); if (!index.HasValue || !IsRowIndexValid(index.Value)) { - SelectedRowIndex = VerticalCursor.None; + SetCurrentValue(SelectedRowIndexProperty, VerticalCursor.None); MultiSelection.Clear(); } else @@ -357,20 +400,20 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) MultiSelection.Add(index.Value); } } - SelectedRowIndex = index.Value; + SetCurrentValue(SelectedRowIndexProperty, index.Value); } } // cell { var columnIndex = GetColumnIndexByX(e.GetPosition(this).X); if (Items?.Count == 0 || !columnIndex.HasValue) - SelectedCellIndex = -1; + SetCurrentValue(SelectedCellIndexProperty, -1); else { if (TableSpan is { } span && span.IsMerged(SelectedRowIndex.GroupIndex, SelectedRowIndex.RowIndex, columnIndex.Value, out var _, out var firstColumn)) columnIndex = firstColumn; - SelectedCellIndex = Math.Clamp(columnIndex.Value, 0, ColumnsCount - 1); + SetCurrentValue(SelectedCellIndexProperty, Math.Clamp(columnIndex.Value, 0, ColumnsCount - 1)); } } } @@ -583,7 +626,7 @@ private void UpdateKeyBindings() if (IsSelectedCellValid) OpenEditor(""); }); - KeyBindings.Add(new BetterKeyBinding() + KeyBindings.Add(new VirtualizedVeryFastTableView.BetterKeyBinding() { Gesture = new KeyGesture(Key.Enter), CustomCommand = new DelegateCommand(() => @@ -592,64 +635,15 @@ private void UpdateKeyBindings() OpenEditor(); }) }); - KeyBindings.Add(new BetterKeyBinding() + KeyBindings.Add(new VirtualizedVeryFastTableView.BetterKeyBinding() { Gesture = new KeyGesture(Key.Back), CustomCommand = openAndErase }); - KeyBindings.Add(new BetterKeyBinding() + KeyBindings.Add(new VirtualizedVeryFastTableView.BetterKeyBinding() { Gesture = new KeyGesture(Key.Delete), CustomCommand = openAndErase }); } - - - /*** - * This is KeyBinding that forwards the gesture to the focused TextBox first - */ - private class BetterKeyBinding : KeyBinding, ICommand - { - public static readonly StyledProperty CustomCommandProperty = AvaloniaProperty.Register(nameof (CustomCommand)); - - public ICommand CustomCommand - { - get => GetValue(CustomCommandProperty); - set => SetValue(CustomCommandProperty, value); - } - - public BetterKeyBinding() - { - Command = this; - } - - public bool CanExecute(object? parameter) - { - if (FocusManager.Instance!.Current is TextBox tb) - return true; - return CustomCommand.CanExecute(parameter); - } - - public void Execute(object? parameter) - { - if (FocusManager.Instance!.Current is TextBox tb) - { - var ev = Activator.CreateInstance(); - ev.Key = Gesture.Key; - ev.KeyModifiers = Gesture.KeyModifiers; - ev.RoutedEvent = InputElement.KeyDownEvent; - tb.RaiseEvent(ev); - if (!ev.Handled && CanExecute(parameter)) - CustomCommand.Execute(parameter); - } - else - CustomCommand.Execute(parameter); - } - - public event EventHandler? CanExecuteChanged - { - add => CustomCommand.CanExecuteChanged += value; - remove => CustomCommand.CanExecuteChanged -= value; - } - } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/FastTableView/WdeCellDrawer.cs b/AvaloniaStyles/Controls/FastTableView/WdeCellDrawer.cs index 26b1fa9e6..6c6437fce 100644 --- a/AvaloniaStyles/Controls/FastTableView/WdeCellDrawer.cs +++ b/AvaloniaStyles/Controls/FastTableView/WdeCellDrawer.cs @@ -1,3 +1,4 @@ +using System.Globalization; using Avalonia; using Avalonia.Media; @@ -46,14 +47,11 @@ public bool Draw(DrawingContext context, IFastTableContext table, ref Rect rect, context.DrawRectangle(ButtonBackgroundPen.Brush, ButtonBorderPen, rect, 4, 4); var state = context.PushClip(rect); - var ft = new FormattedText - { - Text = "Click", - Constraint = new Size(rect.Width, rect.Height), - Typeface = Typeface.Default, - FontSize = 12 - }; - context.DrawText(ButtonTextPen.Brush, new Point(rect.Center.X - ft.Bounds.Width / 2, rect.Center.Y - ft.Bounds.Height / 2), ft); + var ft = new FormattedText("Click", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Typeface.Default, 12, ButtonTextPen.Brush); + ft.MaxTextWidth = float.MaxValue; // rect.Width // we don't want text wrapping so pass float.MaxValue + ft.MaxTextHeight = rect.Height; + + context.DrawText(ft, new Point(rect.Center.X - ft.Width / 2, rect.Center.Y - ft.Height / 2)); state.Dispose(); return true; diff --git a/AvaloniaStyles/Controls/GridView.cs b/AvaloniaStyles/Controls/GridView.cs index 8938d9fc0..fdead31fc 100644 --- a/AvaloniaStyles/Controls/GridView.cs +++ b/AvaloniaStyles/Controls/GridView.cs @@ -13,9 +13,11 @@ using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Avalonia.Metadata; using Avalonia.Styling; using Avalonia.Threading; +using Avalonia.Utilities; using Avalonia.VisualTree; using WDE.MVVM; using WDE.MVVM.Observable; @@ -25,18 +27,20 @@ namespace AvaloniaStyles.Controls { public class GridViewListBox : ListBox { - protected override IItemContainerGenerator CreateItemContainerGenerator() + protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) { - return new ItemContainerGenerator( - this, - ContentControl.ContentProperty, - ContentControl.ContentTemplateProperty); + return new GridViewItem(); + } + + protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) + { + return NeedsContainer(item, out recycleKey); } } - public class GridViewItem : ListBoxItem, IStyleable + public class GridViewItem : ListBoxItem { - Type IStyleable.StyleKey => typeof(ListBoxItem); + protected override Type StyleKeyOverride => typeof(ListBoxItem); static GridViewItem() { ContentProperty.Changed.AddClassHandler((item, args) => @@ -115,8 +119,8 @@ public object? SelectedItem public bool AutoScrollToSelectedItem { - get => GetValue(SelectingItemsControl.AutoScrollToSelectedItemProperty); - set => SetValue(SelectingItemsControl.AutoScrollToSelectedItemProperty, value); + get => GetValue(AutoScrollToSelectedItemProperty); + set => SetValue(AutoScrollToSelectedItemProperty, value); } public static readonly DirectProperty> ColumnsProperty = @@ -143,19 +147,29 @@ public IDataTemplate ItemTemplate public ListBox? ListBoxImpl => listBox; + private ScrollViewer? headerScroll; + private ScrollViewer? contentScroll; + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { + if (headerScroll is { }) + headerScroll.ScrollChanged -= OnHeaderScrollChanged; + if (contentScroll is { }) + contentScroll.ScrollChanged -= OnContentScrollChanged; + base.OnApplyTemplate(e); - header = e.NameScope.Find("PART_header"); - listBox = e.NameScope.Find("PART_listbox"); - + header = e.NameScope.Get("PART_header"); + listBox = e.NameScope.Get("PART_listbox"); + headerScroll = e.NameScope.Get("PART_HeaderScroll"); + contentScroll = e.NameScope.Get("PART_ContentScroll"); + + headerScroll.ScrollChanged += OnHeaderScrollChanged; + contentScroll.ScrollChanged += OnContentScrollChanged; + header.ColumnDefinitions.Clear(); header.Children.Clear(); SetupGridColumns(header, true); - // additional column in header makes it easier to resize - header.ColumnDefinitions.Add(new ColumnDefinition(20, GridUnitType.Pixel)); - int i = 0; foreach (var column in Columns) { @@ -174,17 +188,18 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) } BindFixMultiSelect(); - - void ExecuteScrollWhenLayoutUpdated(object? sender, EventArgs e) - { - LayoutUpdated -= ExecuteScrollWhenLayoutUpdated; - Dispatcher.UIThread.Post(AutoScrollToSelectedItemIfNecessary); - } + } - if (AutoScrollToSelectedItem) - { - LayoutUpdated += ExecuteScrollWhenLayoutUpdated; - } + private void OnContentScrollChanged(object? sender, ScrollChangedEventArgs e) + { + if (contentScroll is not null && headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X)) + headerScroll.Offset = headerScroll.Offset.WithX(contentScroll.Offset.X); + } + + private void OnHeaderScrollChanged(object? sender, ScrollChangedEventArgs e) + { + if (contentScroll is not null && headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X)) + contentScroll.Offset = contentScroll.Offset.WithX(headerScroll.Offset.X); } private void BindFixMultiSelect() @@ -207,7 +222,7 @@ private void BindFixMultiSelect() if (listBox.Selection.Count <= 0) return; - if (e.Source is not IVisual source) + if (e.Source is not Visual source) return; var point = e.GetCurrentPoint(source); @@ -215,13 +230,13 @@ private void BindFixMultiSelect() if (!point.Properties.IsLeftButtonPressed && !point.Properties.IsRightButtonPressed) return; - var containerIndex = GetContainerIndexFromEventSource(listBox, e.Source); + var containerIndex = GetContainerIndexFromEventSource(listBox, e.Source as Interactive); if (!containerIndex.HasValue) return; - var range = e.KeyModifiers.HasAllFlags(KeyModifiers.Shift); - var toggle = e.KeyModifiers.HasAllFlags(KeyModifiers.Control); + var range = e.KeyModifiers.HasFlagFast(KeyModifiers.Shift); + var toggle = e.KeyModifiers.HasFlagFast(KeyModifiers.Control); var isSelected = listBox.Selection.SelectedIndexes.Contains(containerIndex.Value); if (isSelected || toggle || range) @@ -233,7 +248,7 @@ private void BindFixMultiSelect() if (listBox.Selection.Count <= 0) return; - if (e.Source is not IVisual source) + if (e.Source is not Visual source) return; var point = e.GetCurrentPoint(source); @@ -241,7 +256,7 @@ private void BindFixMultiSelect() if (point.Properties.PointerUpdateKind == PointerUpdateKind.LeftButtonReleased || point.Properties.PointerUpdateKind == PointerUpdateKind.RightButtonReleased) { - var containerIndex = GetContainerIndexFromEventSource(listBox, e.Source); + var containerIndex = GetContainerIndexFromEventSource(listBox, e.Source as Interactive); if (containerIndex.HasValue) { @@ -253,8 +268,8 @@ private void BindFixMultiSelect() .Invoke(listBox, new object[] { containerIndex.Value, true, - e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), - e.KeyModifiers.HasAllFlags(KeyModifiers.Control), + e.KeyModifiers.HasFlagFast(KeyModifiers.Shift), + e.KeyModifiers.HasFlagFast(KeyModifiers.Control), point.Properties.PointerUpdateKind == PointerUpdateKind.RightButtonReleased }); e.Handled = true; @@ -269,7 +284,6 @@ private void BindFixMultiSelect() protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { base.OnAttachedToVisualTree(e); - AutoScrollToSelectedItemIfNecessary(); BindFixMultiSelect(); } @@ -280,13 +294,13 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e handlersDisposable = null; } - protected static int? GetContainerIndexFromEventSource(ListBox listBox, IInteractive? eventSource) + protected static int? GetContainerIndexFromEventSource(ListBox listBox, Interactive? eventSource) { - for (var current = eventSource as IVisual; current != null; current = current.VisualParent) + for (var current = eventSource as Visual; current != null; current = current.GetVisualParent()) { - if (current is IControl control && control.LogicalParent == listBox) + if (current is Control control && ReferenceEquals(control.GetLogicalParent(), listBox)) { - int? index = listBox.ItemContainerGenerator?.IndexFromContainer(control); + int? index = listBox.IndexFromContainer(control); return index == -1 ? null : index; } } @@ -314,41 +328,15 @@ private void SetupGridColumns(Grid grid, bool isHeader) grid.ColumnDefinitions.Add(c); grid.ColumnDefinitions.Add(new ColumnDefinition(SplitterWidth, GridUnitType.Pixel)); } - } - - private void AutoScrollToSelectedItemIfNecessary() - { - if (listBox == null) - return; - - if (!AutoScrollToSelectedItem) - return; - - if (SelectedItem == null) - return; - var index = listBox.SelectedIndex; - - var visible = listBox.GetVisualDescendants().Count(t => t is ListBoxItem); - - var scroll = listBox.FindDescendantOfType(); - - if (index < scroll.Offset.Y || index > scroll.Offset.Y + visible) - scroll.Offset = new Vector(scroll.Offset.X, Math.Max(0, index - visible / 2)); + // additional column in header makes it easier to resize + grid.ColumnDefinitions.Add(new ColumnDefinition(20, GridUnitType.Pixel)); } static GridView() { ColumnsProperty.Changed.AddClassHandler(OnColumnsModified); - SelectedItemProperty.Changed.AddClassHandler((view, args) => - { - if (!view.AutoScrollToSelectedItem) - return; - - Dispatcher.UIThread.Post(view.AutoScrollToSelectedItemIfNecessary); - }); - SelectionProperty.Changed.AddClassHandler((view, args) => { view.selectionDisposable?.Dispose(); @@ -380,7 +368,7 @@ protected override void OnKeyDown(KeyEventArgs e) if (list?.SelectedItem == null) return; - var selected = list.ItemContainerGenerator.ContainerFromIndex(list.SelectedIndex); + var selected = list.ContainerFromIndex(list.SelectedIndex); if (selected == null) return; @@ -397,17 +385,17 @@ protected override void OnKeyDown(KeyEventArgs e) public GridView() { - Selection = new SelectionModel(); - ItemTemplate = new FuncDataTemplate(_ => true, (_, _) => + SetCurrentValue(SelectionProperty, new SelectionModel()); + SetCurrentValue(ItemTemplateProperty, new FuncDataTemplate(_ => true, (_, _) => { var parent = ConstructGrid(); int i = 0; foreach (var column in Columns) { - IControl control; + Control control; if (column.DataTemplate is { } dt) { - control = dt.Build(column); + control = dt.Build(column) ?? new TextBlock(){Text = "Couldn't instantiate column"}; } else if (column.Checkable) { @@ -430,7 +418,7 @@ public GridView() parent.Children.Add(control); } return parent; - }, true); + }, true)); } } diff --git a/AvaloniaStyles/Controls/GridViewStyle.axaml b/AvaloniaStyles/Controls/GridViewStyle.axaml index 94019e817..9c7954317 100644 --- a/AvaloniaStyles/Controls/GridViewStyle.axaml +++ b/AvaloniaStyles/Controls/GridViewStyle.axaml @@ -1,36 +1,13 @@ + xmlns:controls="clr-namespace:AvaloniaStyles.Controls" + xmlns:converters="clr-namespace:AvaloniaStyles.Converters"> - - @@ -64,56 +33,32 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/AvaloniaStyles/Controls/GroupingListBox.axaml b/AvaloniaStyles/Controls/GroupingListBox.axaml index 1b1b5dcb4..2781437fb 100644 --- a/AvaloniaStyles/Controls/GroupingListBox.axaml +++ b/AvaloniaStyles/Controls/GroupingListBox.axaml @@ -35,16 +35,14 @@ BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> - + - + @@ -61,11 +59,8 @@ + Margin="{TemplateBinding Padding}"/> diff --git a/AvaloniaStyles/Controls/GroupingListBox.axaml.cs b/AvaloniaStyles/Controls/GroupingListBox.axaml.cs index 1cc03f621..a1291dde1 100644 --- a/AvaloniaStyles/Controls/GroupingListBox.axaml.cs +++ b/AvaloniaStyles/Controls/GroupingListBox.axaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Linq; using Avalonia; using Avalonia.Collections; using Avalonia.Controls; @@ -8,6 +9,7 @@ using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Avalonia.Metadata; using Avalonia.Styling; using Avalonia.VisualTree; @@ -31,41 +33,41 @@ public object? GroupName set => SetAndRaise(GroupNameProperty, ref groupName, value); } - public static readonly DirectProperty CustomContentProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty CustomContentProperty = + AvaloniaProperty.RegisterDirect( nameof(CustomContent), o => o.CustomContent, (o, v) => o.CustomContent = v); - private IControl? customContent; - public IControl? CustomContent + private Control? customContent; + public Control? CustomContent { get => customContent; set => SetAndRaise(CustomContentProperty, ref customContent, value); } - public static readonly DirectProperty CustomRightContentProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty CustomRightContentProperty = + AvaloniaProperty.RegisterDirect( nameof(CustomRightContent), o => o.CustomRightContent, (o, v) => o.CustomRightContent = v); - private IControl? customRightContent; - public IControl? CustomRightContent + private Control? customRightContent; + public Control? CustomRightContent { get => customRightContent; set => SetAndRaise(CustomRightContentProperty, ref customRightContent, value); } - public static readonly DirectProperty CustomCenterContentProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty CustomCenterContentProperty = + AvaloniaProperty.RegisterDirect( nameof(CustomCenterContent), o => o.CustomCenterContent, (o, v) => o.CustomCenterContent = v); - private IControl? customCenterContent; - public IControl? CustomCenterContent + private Control? customCenterContent; + public Control? CustomCenterContent { get => customCenterContent; set => SetAndRaise(CustomCenterContentProperty, ref customCenterContent, value); @@ -106,16 +108,16 @@ public IEnumerable Items set => SetAndRaise(ItemsProperty, ref items, value); } - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new StackPanel()); + private static readonly FuncTemplate DefaultPanel = + new FuncTemplate(() => new StackPanel()); - public static readonly StyledProperty> ItemsPanelProperty = - AvaloniaProperty.Register>(nameof(ItemsPanel), DefaultPanel); + public static readonly StyledProperty> ItemsPanelProperty = + AvaloniaProperty.Register>(nameof(ItemsPanel), DefaultPanel); public static readonly StyledProperty ItemTemplateProperty = AvaloniaProperty.Register(nameof(ItemTemplate)); - public ITemplate ItemsPanel + public ITemplate ItemsPanel { get => GetValue(ItemsPanelProperty); set => SetValue(ItemsPanelProperty, value); @@ -153,8 +155,9 @@ public void ScrollToItem(object item) if (index == -1) return; - var container = parentItems.ItemContainerGenerator.ContainerFromIndex(index); - scroll.Offset = new Vector(0, container.Bounds.Y); + var container = parentItems.ContainerFromIndex(index); + if (container != null) + scroll.Offset = new Vector(0, container.Bounds.Y); } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -180,7 +183,7 @@ public void FocusElement(int parentIndex, int innerIndex) return; listBox.SelectedIndex = innerIndex; - (listBox.ItemContainerGenerator.ContainerFromIndex(listBox.SelectedIndex)).Focus(); + (listBox.ContainerFromIndex(listBox.SelectedIndex))?.Focus(); } #region KEYBOARD_NAVIGATION @@ -207,14 +210,17 @@ private void OnPreviewKeyDown(object? sender, KeyEventArgs e) { e.Handled = true; var dir = e.Key == Key.Up ? -1 : 1; - int itemsInRow = (int)(that.Bounds.Width / ((that.ItemContainerGenerator.ContainerFromIndex(0)).Bounds.Width)); + var element = that.ContainerFromIndex(0); + if (element == null) + return; + int itemsInRow = (int)(that.Bounds.Width / (element.Bounds.Width)); MoveUpDown(that, parent, itemsInRow, dir); } } private ListBox? GetNextParent(ItemsControl parent, ListBox current, int dir) { - var currentParentIndex = ((IList)parent.Items).IndexOf(current.DataContext); + var currentParentIndex = ((IList?)parent.Items)?.IndexOf(current.DataContext) ?? -1; var nextParentIndex = currentParentIndex + dir; if (nextParentIndex < 0 || nextParentIndex > parent.ItemCount - 1) return null; @@ -223,10 +229,13 @@ private void OnPreviewKeyDown(object? sender, KeyEventArgs e) private ListBox? GetListBoxFromItemsControl(ItemsControl parent, int index) { - var x = parent.ItemContainerGenerator.ContainerFromIndex(index); - if (x == null || x.LogicalChildren.Count == 0 || x.LogicalChildren[0].LogicalChildren.Count < 2) + var x = parent.ContainerFromIndex(index); + if (x == null) + return null; + var logicalChildren = x.GetLogicalChildren().ToList(); + if (x == null || logicalChildren.Count == 0 || logicalChildren[0].LogicalChildren.Count < 2) return null; - return (ListBox) x.LogicalChildren[0].LogicalChildren[1]; + return (ListBox) logicalChildren[0].LogicalChildren[1]; } private void MoveNextPrev(ListBox listBox, ItemsControl parent, int dir) @@ -294,17 +303,17 @@ private int FindIndexInColumn(int startIndex, int length, int column, int column private void SelectIndex(ListBox listbox, int index) { listbox.SelectedIndex = index; - (listbox.ItemContainerGenerator.ContainerFromIndex(listbox.SelectedIndex)).Focus(); + listbox.ContainerFromIndex(listbox.SelectedIndex)?.Focus(); } - public static T? FindParent(IVisual? obj) where T : Control + public static T? FindParent(Visual? obj) where T : Control { - obj = obj?.VisualParent; + obj = obj?.GetVisualParent(); while (obj != null) { if (obj is T parent) return parent; - obj = obj.VisualParent; + obj = obj.GetVisualParent(); } return null; @@ -312,9 +321,9 @@ private void SelectIndex(ListBox listbox, int index) #endregion } - internal class GroupingListBoxInner : ListBox, IStyleable + internal class GroupingListBoxInner : ListBox { - Type IStyleable.StyleKey => typeof(ListBox); + protected override Type StyleKeyOverride => typeof(ListBox); public static readonly DirectProperty CustomSelectedItemProperty = AvaloniaProperty.RegisterDirect( @@ -352,7 +361,7 @@ static GroupingListBoxInner() inEvent = true; { o.CustomSelectedItem = arg.NewValue; - GroupingListBox parent = o.FindAncestorOfType(); + GroupingListBox? parent = o.FindAncestorOfType(); if (parent != null) parent.SelectedItem = arg.NewValue; o.RaisePropertyChanged(CustomSelectedItemProperty, arg.OldValue, arg.NewValue); @@ -362,6 +371,6 @@ static GroupingListBoxInner() }); } - private bool IsAttached() => ((IVisual) this).IsAttachedToVisualTree; + private bool IsAttached() => ((Visual) this).GetVisualRoot() != null; } } \ No newline at end of file diff --git a/AvaloniaStyles/Controls/HamburgerMenuButton.axaml b/AvaloniaStyles/Controls/HamburgerMenuButton.axaml new file mode 100644 index 000000000..e04e1916c --- /dev/null +++ b/AvaloniaStyles/Controls/HamburgerMenuButton.axaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AvaloniaStyles/Controls/HamburgerMenuButton.axaml.cs b/AvaloniaStyles/Controls/HamburgerMenuButton.axaml.cs new file mode 100644 index 000000000..4639c8d46 --- /dev/null +++ b/AvaloniaStyles/Controls/HamburgerMenuButton.axaml.cs @@ -0,0 +1,9 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; + +namespace AvaloniaStyles.Controls; + +public class HamburgerMenuButton : TemplatedControl +{ +} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/IconElement/BitmapIcon.cs b/AvaloniaStyles/Controls/IconElement/BitmapIcon.cs index afa82c513..622e04b3a 100644 --- a/AvaloniaStyles/Controls/IconElement/BitmapIcon.cs +++ b/AvaloniaStyles/Controls/IconElement/BitmapIcon.cs @@ -6,19 +6,24 @@ using Avalonia.Skia; using SkiaSharp; using System; -using Avalonia.Visuals.Media.Imaging; namespace AvaloniaStyles.Controls; public partial class BitmapIcon : FAIconElement { + public BitmapIcon() + { + RenderOptions.SetBitmapInterpolationMode(this, BitmapInterpolationMode.HighQuality); + } + ~BitmapIcon() { Dispose(); UnlinkFromBitmapIconSource(); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + /// + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == UriSourceProperty) @@ -26,7 +31,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs if (_bis != null) throw new InvalidOperationException("Cannot edit properties of BitmapIcon if BitmapIconSource is linked"); - CreateBitmap(UriSource); + CreateBitmap(change.GetNewValue()); InvalidateVisual(); } else if (change.Property == ShowAsMonochromeProperty) @@ -38,6 +43,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs } } + /// protected override Size MeasureOverride(Size availableSize) { if (_bis != null) @@ -49,6 +55,7 @@ protected override Size MeasureOverride(Size availableSize) return _originalSize; } + /// public override void Render(DrawingContext context) { if (_bitmap == null && _bis == null) @@ -64,42 +71,43 @@ public override void Render(DrawingContext context) var wid = (int)dst.Width; var hei = (int)dst.Height; - using (var bmp = new RenderTargetBitmap(new PixelSize(wid, hei))) - using (var ctx = bmp.PlatformImpl.Item.CreateDrawingContext(null)) + using (var bmp = new WriteableBitmap(new PixelSize(wid, hei), new Vector(96, 96), + PixelFormats.Bgra8888, AlphaFormat.Premul)) { - throw new NotImplementedException(); // todo Avalonia 11 - //var feat = ctx.GetFeature(); - //if (feat == null) - // throw new Exception("BitmapIcon requires SkiaSharp to be rendering backend"); - //using var lease = feat.Lease(); - //var skDC = lease.SkCanvas; -// - //skDC.Clear(new SKColor(0, 0, 0, 0)); -// - //var finalBmp = _bitmap.Resize(new SKImageInfo(wid, hei), SKFilterQuality.High); -// - //if (ShowAsMonochrome) - //{ - // var avColor = Foreground is ISolidColorBrush sc ? sc.Color : Colors.White; -// - // var color = new SKColor(avColor.R, avColor.G, avColor.B, avColor.A); - // SKPaint paint = new SKPaint(); - // paint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.SrcATop); -// - // skDC.DrawBitmap(finalBmp, new SKRect(0, 0, (float)wid, (float)hei), paint); - // paint.Dispose(); - //} - //else - //{ - // skDC.DrawBitmap(finalBmp, new SKRect(0, 0, (float)wid, (float)hei)); - //} -// - //finalBmp.Dispose(); -// - //using (context.PushClip(dst)) - //{ - // context.DrawImage(bmp, new Rect(bmp.Size), dst, BitmapInterpolationMode.HighQuality); - //} + using var buffer = bmp.Lock(); + + var skSfc = SKSurface.Create(new SKImageInfo(wid, hei), buffer.Address); + if (skSfc == null) + return; + + var skDC = skSfc.Canvas; + + skDC.Clear(new SKColor(0, 0, 0, 0)); + + var finalBmp = _bitmap.Resize(new SKImageInfo(wid, hei), SKFilterQuality.High); + + if (ShowAsMonochrome) + { + var avColor = Foreground is ISolidColorBrush sc ? sc.Color : Colors.White; + + var color = new SKColor(avColor.R, avColor.G, avColor.B, avColor.A); + SKPaint paint = new SKPaint(); + paint.ColorFilter = SKColorFilter.CreateBlendMode(color, SKBlendMode.SrcATop); + + skDC.DrawBitmap(finalBmp, new SKRect(0, 0, (float)wid, (float)hei), paint); + paint.Dispose(); + } + else + { + skDC.DrawBitmap(finalBmp, new SKRect(0, 0, (float)wid, (float)hei)); + } + + finalBmp.Dispose(); + + using (context.PushClip(dst)) + { + context.DrawImage(bmp, new Rect(bmp.Size), dst); + } } } @@ -119,12 +127,12 @@ private void CreateBitmap(Uri src) } else { - var assets = AvaloniaLocator.Current.GetService(); - _bitmap = SKBitmap.Decode(assets.Open(src)); + _bitmap = SKBitmap.Decode(AssetLoader.Open(src)); } _originalSize = new Size(_bitmap.Width, _bitmap.Height); } + /// protected void Dispose() { _bitmap?.Dispose(); diff --git a/AvaloniaStyles/Controls/IconElement/BitmapIconSource.cs b/AvaloniaStyles/Controls/IconElement/BitmapIconSource.cs index 189aa0ce6..c3cb64b06 100644 --- a/AvaloniaStyles/Controls/IconElement/BitmapIconSource.cs +++ b/AvaloniaStyles/Controls/IconElement/BitmapIconSource.cs @@ -50,13 +50,13 @@ public bool ShowAsMonochrome public event EventHandler OnBitmapChanged; - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == UriSourceProperty) { - CreateBitmap(UriSource); + CreateBitmap(change.GetNewValue()); } else if (change.Property == ShowAsMonochromeProperty) { @@ -87,8 +87,7 @@ private void CreateBitmap(Uri src) } else { - var assets = AvaloniaLocator.Current.GetService(); - _bitmap = SKBitmap.Decode(assets.Open(src)); + _bitmap = SKBitmap.Decode(AssetLoader.Open(src)); } _originalSize = new Size(_bitmap.Width, _bitmap.Height); diff --git a/AvaloniaStyles/Controls/IconElement/FAIconElement.cs b/AvaloniaStyles/Controls/IconElement/FAIconElement.cs index 8c4b15393..8be920b25 100644 --- a/AvaloniaStyles/Controls/IconElement/FAIconElement.cs +++ b/AvaloniaStyles/Controls/IconElement/FAIconElement.cs @@ -5,6 +5,7 @@ using System; using System.ComponentModel; using System.Globalization; +using Avalonia.Controls.Documents; namespace AvaloniaStyles.Controls; @@ -18,7 +19,7 @@ public class FAIconElement : Control /// Defines the property /// public static readonly AttachedProperty ForegroundProperty = - TextBlock.ForegroundProperty.AddOwner(); + TextElement.ForegroundProperty.AddOwner(); /// /// Gets or sets a brush that describes the foreground color. @@ -29,7 +30,7 @@ public IBrush Foreground set => SetValue(ForegroundProperty, value); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); diff --git a/AvaloniaStyles/Controls/IconElement/FAPathIcon.cs b/AvaloniaStyles/Controls/IconElement/FAPathIcon.cs index 579c5e449..9e4ebe8c1 100644 --- a/AvaloniaStyles/Controls/IconElement/FAPathIcon.cs +++ b/AvaloniaStyles/Controls/IconElement/FAPathIcon.cs @@ -18,7 +18,7 @@ static FAPathIcon() ClipToBoundsProperty.OverrideDefaultValue(true); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); @@ -187,7 +187,7 @@ public override void Render(DrawingContext context) if (geometry == null) return; - using var s = context.PushPostTransform(_transform); // todo: post transsform? + using var s = context.PushTransform(_transform); context.DrawGeometry(Foreground, null, geometry); } diff --git a/AvaloniaStyles/Controls/IconElement/FAPathIcon.properties.cs b/AvaloniaStyles/Controls/IconElement/FAPathIcon.properties.cs index ef21f5f3b..7efe4e281 100644 --- a/AvaloniaStyles/Controls/IconElement/FAPathIcon.properties.cs +++ b/AvaloniaStyles/Controls/IconElement/FAPathIcon.properties.cs @@ -15,7 +15,7 @@ public partial class FAPathIcon : FAIconElement /// /// Defines the property /// - public static StyledProperty DataProperty = + public static readonly StyledProperty DataProperty = Path.DataProperty.AddOwner(); /// diff --git a/AvaloniaStyles/Controls/IconElement/FontIcon.cs b/AvaloniaStyles/Controls/IconElement/FontIcon.cs index 9fa80041b..55b198100 100644 --- a/AvaloniaStyles/Controls/IconElement/FontIcon.cs +++ b/AvaloniaStyles/Controls/IconElement/FontIcon.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Documents; using Avalonia.Media; using Avalonia.Media.TextFormatting; using Avalonia.Threading; @@ -14,20 +15,20 @@ namespace AvaloniaStyles.Controls; /// public partial class FontIcon : FAIconElement { - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); - if (change.Property == TextBlock.FontSizeProperty || - change.Property == TextBlock.FontFamilyProperty || - change.Property == TextBlock.FontWeightProperty || - change.Property == TextBlock.FontStyleProperty || + if (change.Property == TextElement.FontSizeProperty || + change.Property == TextElement.FontFamilyProperty || + change.Property == TextElement.FontWeightProperty || + change.Property == TextElement.FontStyleProperty || change.Property == GlyphProperty) { _textLayout = null; InvalidateMeasure(); } - else if (change.Property == TextBlock.ForegroundProperty) + else if (change.Property == TextElement.ForegroundProperty) { _textLayout = null; // FAIconElement calls InvalidateVisual @@ -41,7 +42,7 @@ protected override Size MeasureOverride(Size availableSize) GenerateText(); } - return _textLayout.Size; + return new Size(_textLayout.Width, _textLayout.Height); } public override void Render(DrawingContext context) @@ -52,10 +53,9 @@ public override void Render(DrawingContext context) var dstRect = new Rect(Bounds.Size); using (context.PushClip(dstRect)) { - var pt = new Point(dstRect.Center.X - _textLayout.Size.Width / 2, - dstRect.Center.Y - _textLayout.Size.Height / 2); - using var _ = context.PushPreTransform(Matrix.CreateTranslation(pt)); - _textLayout.Draw(context); // , pt todo Avalonia 11 + var pt = new Point(dstRect.Center.X - _textLayout.Width / 2, + dstRect.Center.Y - _textLayout.Height / 2); + _textLayout.Draw(context, pt); } } diff --git a/AvaloniaStyles/Controls/IconElement/IconSourceElement.cs b/AvaloniaStyles/Controls/IconElement/IconSourceElement.cs index 9ef85c548..759f23703 100644 --- a/AvaloniaStyles/Controls/IconElement/IconSourceElement.cs +++ b/AvaloniaStyles/Controls/IconElement/IconSourceElement.cs @@ -25,7 +25,7 @@ public IconSource IconSource set => SetValue(IconSourceProperty, value); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); diff --git a/AvaloniaStyles/Controls/IconElement/ImageIcon.cs b/AvaloniaStyles/Controls/IconElement/ImageIcon.cs index d4c347b34..60141d64b 100644 --- a/AvaloniaStyles/Controls/IconElement/ImageIcon.cs +++ b/AvaloniaStyles/Controls/IconElement/ImageIcon.cs @@ -2,7 +2,6 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Metadata; -using Avalonia.Visuals.Media.Imaging; namespace AvaloniaStyles.Controls; @@ -27,7 +26,7 @@ public IImage Source set => SetValue(SourceProperty, value); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == SourceProperty) @@ -59,7 +58,7 @@ public override void Render(DrawingContext context) Rect srcRect = new Rect(src.Size) .CenterRect(new Rect(destRect.Size / scale)); - context.DrawImage(src, srcRect, destRect, BitmapInterpolationMode.HighQuality); + context.DrawImage(src, srcRect, destRect); } } } diff --git a/AvaloniaStyles/Controls/IconElement/PathIconSource.cs b/AvaloniaStyles/Controls/IconElement/PathIconSource.cs index d37ede9a6..e3d6fd74c 100644 --- a/AvaloniaStyles/Controls/IconElement/PathIconSource.cs +++ b/AvaloniaStyles/Controls/IconElement/PathIconSource.cs @@ -17,7 +17,7 @@ static PathIconSource() /// /// Defines the property /// - public static StyledProperty DataProperty = + public static readonly StyledProperty DataProperty = FAPathIcon.DataProperty.AddOwner(); /// @@ -34,7 +34,7 @@ public Geometry Data /// Defines the property. /// public static readonly StyledProperty StretchProperty = - FAPathIcon.StretchProperty.AddOwner(); + FAPathIcon.StretchProperty.AddOwner(); /// /// Gets or sets a enumeration value that describes how the shape fills its allocated space. @@ -49,7 +49,7 @@ public Stretch Stretch /// Defines the property. /// public static readonly StyledProperty StretchDirectionProperty = - FAPathIcon.StretchDirectionProperty.AddOwner(); + FAPathIcon.StretchDirectionProperty.AddOwner(); /// /// Gets or sets a value controlling in what direction contents will be stretched. diff --git a/AvaloniaStyles/Controls/IconElement/SymbolIcon.cs b/AvaloniaStyles/Controls/IconElement/SymbolIcon.cs index 644d9ded5..3e1e9b80c 100644 --- a/AvaloniaStyles/Controls/IconElement/SymbolIcon.cs +++ b/AvaloniaStyles/Controls/IconElement/SymbolIcon.cs @@ -47,7 +47,7 @@ public double FontSize set => SetValue(FontSizeProperty, value); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == TextBlock.FontSizeProperty || @@ -77,7 +77,7 @@ protected override Size MeasureOverride(Size availableSize) if (_textLayout == null) GenerateText(); - return _textLayout?.Size ?? default; + return new Size(_textLayout.Width, _textLayout.Height); } public override void Render(DrawingContext context) @@ -88,10 +88,9 @@ public override void Render(DrawingContext context) var dstRect = new Rect(Bounds.Size); using (context.PushClip(dstRect)) { - var pt = new Point(dstRect.Center.X - _textLayout.Size.Width / 2, - dstRect.Center.Y - _textLayout.Size.Height / 2); - using var _ = context.PushPostTransform(Matrix.CreateTranslation(pt)); - _textLayout.Draw(context); // , pt todo Avalonia 11 + var pt = new Point(dstRect.Center.X - _textLayout.Width / 2, + dstRect.Center.Y - _textLayout.Height / 2); + _textLayout.Draw(context, pt); } } diff --git a/AvaloniaStyles/Controls/InfoBar/InfoBar.cs b/AvaloniaStyles/Controls/InfoBar/InfoBar.cs index c8dbe59fe..7cf0e9a83 100644 --- a/AvaloniaStyles/Controls/InfoBar/InfoBar.cs +++ b/AvaloniaStyles/Controls/InfoBar/InfoBar.cs @@ -39,7 +39,7 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) UpdateForeground(); } - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == IsOpenProperty) @@ -77,7 +77,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs } } - protected override bool RegisterContentPresenter(IContentPresenter presenter) + protected override bool RegisterContentPresenter(ContentPresenter presenter) { if (presenter.Name == "ContentPresenter") return true; @@ -89,7 +89,7 @@ private void OnCloseButtonClick(object? sender, RoutedEventArgs e) { CloseButtonClick?.Invoke(this, EventArgs.Empty); _lastCloseReason = InfoBarCloseReason.CloseButton; - IsOpen = false; + SetCurrentValue(IsOpenProperty, false); } private void RaiseClosingEvent() @@ -107,7 +107,7 @@ private void RaiseClosingEvent() { // The developer has changed the Cancel property to true, // so we need to revert the IsOpen property to true. - IsOpen = true; + SetCurrentValue(IsOpenProperty, true); } } diff --git a/AvaloniaStyles/Controls/LightSolidColorBrush.cs b/AvaloniaStyles/Controls/LightSolidColorBrush.cs deleted file mode 100644 index 486e14562..000000000 --- a/AvaloniaStyles/Controls/LightSolidColorBrush.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Avalonia; -using Avalonia.Media; -using Avalonia.Media.Immutable; -using Avalonia.Metadata; -using AvaloniaStyles.Utils; - -namespace AvaloniaStyles.Controls; - -public class LightSolidColorBrush : Brush, ISolidColorBrush -{ - public override IBrush ToImmutable() => new ImmutableSolidColorBrush(this); - - public static readonly StyledProperty BaseProperty = - AvaloniaProperty.Register(nameof(Base)); - - public static readonly StyledProperty LightProperty = - AvaloniaProperty.Register(nameof(Light)); - - [Content] - public ISolidColorBrush Base - { - get => GetValue(BaseProperty); - set => SetValue(BaseProperty, value); - } - - public double Light - { - get => GetValue(LightProperty); - set => SetValue(LightProperty, value); - } - - public Color Color - { - get - { - var baseBrush = Base; - var hsl = HslColor.FromRgba(baseBrush.Color); - hsl = hsl.WithLightness(hsl.V + Light); - return hsl.ToRgba(baseBrush.Opacity); - } - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/ManagedMenu.cs b/AvaloniaStyles/Controls/ManagedMenu.cs deleted file mode 100644 index 12278f3c1..000000000 --- a/AvaloniaStyles/Controls/ManagedMenu.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Avalonia; -using Avalonia.Controls; - -namespace AvaloniaStyles.Controls; - -/// -/// for some reason, .net 7.0 and this old Avalonia version doesn't like the NativeMenu class -/// probably in Avalonia 11 it is fixed, but for now I've disabled NativeMenu -/// for Ava11, remove this and change all ManagedMenu references to NativeMenu -/// -public class ManagedMenu -{ - public static readonly AttachedProperty MenuProperty - = AvaloniaProperty.RegisterAttached("Menu"); - - public static void SetMenu(AvaloniaObject o, NativeMenu menu) => o.SetValue(MenuProperty, menu); - - public static NativeMenu GetMenu(AvaloniaObject o) => o.GetValue(MenuProperty); - - static ManagedMenu() - { - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/NumberIndicatorControl/NumberIndicator.axaml b/AvaloniaStyles/Controls/NumberIndicatorControl/NumberIndicator.axaml index 9857c29cd..d1481f965 100644 --- a/AvaloniaStyles/Controls/NumberIndicatorControl/NumberIndicator.axaml +++ b/AvaloniaStyles/Controls/NumberIndicatorControl/NumberIndicator.axaml @@ -10,7 +10,7 @@ - + str) - { - var len = str.Length; - for (int i = 0; i < len; ++i) - { - if (str[i] >= 0x3FF) - return true; + LOG.LogError(e); } - - return false; } public void AutoFitColumnsWidth() @@ -88,15 +60,15 @@ public void AutoFitColumnsWidth() return; var controller = Controller; - GetFonts(out var defaultFont, out _); + var defaultFont = TextElement.GetFontFamily(this); var defaultTypeface = new Typeface(defaultFont); var boldTypeface = new Typeface(defaultFont,default, FontWeight.Bold); Span columnWidths = stackalloc double[columns.Count]; var (firstVisibleIndex, lastVisibleIndex) = GetFirstAndLastVisibleRows(); for (int i = 0; i < columns.Count; i++) { - var ft = new FormattedText(columns[i].Header, boldTypeface, 12, TextAlignment.Left, TextWrapping.NoWrap, new Size(100000, 10000)); - columnWidths[i] = ft.Bounds.Width + ColumnSpacing * 2 + 20; // this +20 is only for SqlEditor which displays a key icon for primary key columns. + var ft = new FormattedText(columns[i].Header, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, boldTypeface, 12, Brushes.Black); + columnWidths[i] = ft.Width + ColumnSpacing * 2 + 20; // this +20 is only for SqlEditor which displays a key icon for primary key columns. // If this control is reused for another editor, then it might be changed, but still pls keep // the space in case of SqlEditor. } @@ -106,8 +78,8 @@ public void AutoFitColumnsWidth() for (int cellIndex = 0; cellIndex < columnWidths.Length; ++cellIndex) { var cellText = controller.GetCellText(rowIndex, cellIndex); - var ft = new FormattedText(cellText, defaultTypeface, 12, TextAlignment.Left, TextWrapping.NoWrap, new Size(100000, 10000)); - columnWidths[cellIndex] = Math.Max(columnWidths[cellIndex], ft.Bounds.Width + ColumnSpacing * 2); + var ft = new FormattedText(cellText ?? "", CultureInfo.InvariantCulture, FlowDirection.LeftToRight, defaultTypeface, 12, Brushes.Black); + columnWidths[cellIndex] = Math.Max(columnWidths[cellIndex], ft.Width + ColumnSpacing * 2); } } @@ -132,8 +104,8 @@ public void AutoFitColumnsWidth() private void RenderImpl(DrawingContext context) { - GetTypefaces(out var font, out var unicodeFallback); - + var font = new Typeface(TextElement.GetFontFamily(this)); + var actualWidth = Bounds.Width; var viewPort = DataViewport; @@ -207,22 +179,18 @@ private void RenderImpl(DrawingContext context) text = text.Substring(0, indexOfEndOfLine); rect = rect.WithWidth(rect.Width - ColumnSpacing); - var ft = new FormattedText + var ft = new FormattedText(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, font, 12, textColor) { - Text = text, - Constraint = new Size(rect.Width, RowHeight), - Typeface = UseFallbackUnicodeFont(text) ? unicodeFallback : font, - FontSize = 12 + MaxTextHeight = RowHeight, + MaxTextWidth = float.MaxValue // rect.Width // we don't want text wrapping so pass float.MaxValue }; + if (Math.Abs(rectWidth - rect.Width) > 0.01) { state.Dispose(); state = context.PushClip(rect); } - - context.DrawText(textColor, - new Point(rect.X + ColumnSpacing, y + RowHeight / 2 - ft.Bounds.Height / 2), - ft); + context.DrawText(ft, new Point(rect.X + ColumnSpacing, rect.Center.Y - ft.Height / 2)); } } } @@ -257,7 +225,7 @@ private void RenderHeaders(DrawingContext context) var controller = Controller; FontFamily font = FontFamily.Default; - if (Application.Current!.Styles.TryGetResource("MainFontSans", out var mainFontSans) && mainFontSans is FontFamily mainFontSansFamily) + if (Application.Current!.Styles.TryGetResource("MainFontSans", SystemTheme.EffectiveThemeVariant, out var mainFontSans) && mainFontSans is FontFamily mainFontSansFamily) font = mainFontSansFamily; var scrollViewer = ScrollViewer; @@ -281,12 +249,10 @@ private void RenderHeaders(DrawingContext context) continue; var column = Columns[i]; - var ft = new FormattedText + var ft = new FormattedText(column.Header, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(font, FontStyle.Normal, FontWeight.Bold), 12, BorderPen.Brush) { - Text = column.Header, - Constraint = new Size(column.Width, RowHeight), - Typeface = new Typeface(font, FontStyle.Normal, FontWeight.Bold), - FontSize = 12 + MaxTextHeight = RowHeight, + MaxTextWidth = float.MaxValue // column.Width // we don't want text wrapping so pass float.MaxValue }; bool isMouseOverColumn = isMouseOverHeader && lastMouseLocation.X >= x && lastMouseLocation.X < x + column.Width; @@ -296,7 +262,7 @@ private void RenderHeaders(DrawingContext context) var cellRect = new Rect(x + ColumnSpacing, y, Math.Max(0, column.Width - ColumnSpacing * 2), RowHeight); controller.DrawHeader(i, context, this, ref cellRect); var state = context.PushClip(cellRect); - context.DrawText(BorderPen.Brush, new Point(cellRect.X, cellRect.Center.Y - ft.Bounds.Height / 2), ft); + context.DrawText(ft, new Point(cellRect.X, cellRect.Center.Y - ft.Height / 2)); state.Dispose(); x += column.Width; @@ -357,4 +323,4 @@ private int GetRowIndexByY(double mouseY) return index; return -1; } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/OptimizedVeryFastTableView/VirtualizedVeryFastTableView.cs b/AvaloniaStyles/Controls/OptimizedVeryFastTableView/VirtualizedVeryFastTableView.cs index 6486f12ba..6baa971b4 100644 --- a/AvaloniaStyles/Controls/OptimizedVeryFastTableView/VirtualizedVeryFastTableView.cs +++ b/AvaloniaStyles/Controls/OptimizedVeryFastTableView/VirtualizedVeryFastTableView.cs @@ -3,17 +3,21 @@ using System.Windows.Input; using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Input; using Avalonia.Media; +using Avalonia.Styling; using Avalonia.Threading; using Avalonia.VisualTree; +using AvaloniaEdit; +using AvaloniaEdit.Editing; using AvaloniaStyles.Controls.FastTableView; using WDE.Common.Utils; using WDE.MVVM.Observable; namespace AvaloniaStyles.Controls.OptimizedVeryFastTableView; -public partial class VirtualizedVeryFastTableView : Panel, IKeyboardNavigationHandler +public partial class VirtualizedVeryFastTableView : RenderedPanel, ICustomKeyboardNavigation { protected static double ColumnSpacing = 10; protected static double RowHeight = 28; @@ -39,7 +43,7 @@ public partial class VirtualizedVeryFastTableView : Panel, IKeyboardNavigationHa private static bool GetResource(string key, T defaultVal, out T outT) { outT = defaultVal; - if (Application.Current!.Styles.TryGetResource(key, out var res) && res is T t) + if (Application.Current!.Styles.TryGetResource(key, SystemTheme.EffectiveThemeVariant, out var res) && res is T t) { outT = t; return true; @@ -139,16 +143,19 @@ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { InvalidateMeasure(); InvalidateArrange(); + InvalidateVisual(); }); if (ScrollViewer is { } sc) { sc.GetObservable(ScrollViewer.OffsetProperty).SubscribeAction(_ => { InvalidateArrange(); + InvalidateVisual(); }); sc.GetObservable(BoundsProperty).SubscribeAction(_ => { InvalidateArrange(); + InvalidateVisual(); }); } } @@ -213,13 +220,13 @@ protected override void OnTextInput(TextInputEventArgs e) e.Handled = true; } } - - protected override void OnPointerLeave(PointerEventArgs e) + + protected override void OnPointerExited(PointerEventArgs e) { - Cursor = Cursor.Default; + SetCurrentValue(CursorProperty, Cursor.Default); lastMouseLocation = new Point(-1, -1); InvalidateVisual(); - base.OnPointerLeave(e); + base.OnPointerExited(e); } protected override void OnPointerMoved(PointerEventArgs e) @@ -229,7 +236,7 @@ protected override void OnPointerMoved(PointerEventArgs e) var point = currentPoint.Position; lastMouseLocation = point; lastMouseButtonPressed = currentPoint.Properties.IsLeftButtonPressed; - Cursor = (currentlyResizedColumn.HasValue || IsPointHeader(point) && IsOverColumnSplitter(lastMouseLocation.X, out _)) ? new Cursor(StandardCursorType.SizeWestEast) : Cursor.Default; + SetCurrentValue(CursorProperty, (currentlyResizedColumn.HasValue || IsPointHeader(point) && IsOverColumnSplitter(lastMouseLocation.X, out _)) ? new Cursor(StandardCursorType.SizeWestEast) : Cursor.Default); if (Controller.UpdateCursor(currentPoint.Position, currentPoint.Properties.IsLeftButtonPressed)) InvalidateVisual(); @@ -267,7 +274,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) var index = GetRowIndexByY(e.GetPosition(this).Y); if (!IsRowIndexValid(index)) { - SelectedRowIndex = -1; + SetCurrentValue(SelectedRowIndexProperty, -1); MultiSelection.Clear(); } else @@ -308,16 +315,16 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) MultiSelection.Add(index); } } - SelectedRowIndex = index; + SetCurrentValue(SelectedRowIndexProperty, index); } } // cell { var index = GetColumnIndexByX(e.GetPosition(this).X); if (ItemsCount == 0 || !index.HasValue) - SelectedCellIndex = -1; + SetCurrentValue(SelectedCellIndexProperty, -1); else - SelectedCellIndex = Math.Clamp(index.Value, 0, ColumnsCount - 1); + SetCurrentValue(SelectedCellIndexProperty, Math.Clamp(index.Value, 0, ColumnsCount - 1)); } } else if (IsOverColumnSplitter(e.GetPosition(this).X, out var columnIndex)) @@ -337,9 +344,9 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) { var index = GetColumnIndexByX(e.GetPosition(this).X); if (ItemsCount == 0 || !index.HasValue) - SelectedCellIndex = -1; + SetCurrentValue(SelectedCellIndexProperty, -1); else - SelectedCellIndex = Math.Clamp(index.Value, 0, ColumnsCount - 1); + SetCurrentValue(SelectedCellIndexProperty, Math.Clamp(index.Value, 0, ColumnsCount - 1)); } } e.Handled = true; @@ -422,7 +429,6 @@ private void OpenEditor(string? customText = null) { var originalText = Controller.GetCellText(SelectedRowIndex, SelectedCellIndex); var initialText = customText ?? originalText ?? ""; - GetFonts(out var defaultFont, out var unicodeFallback); editor.Spawn(this, SelectedCellRect, initialText, customText == null, (text, action) => { if (originalText != text) @@ -432,19 +438,19 @@ private void OpenEditor(string? customText = null) switch (action) { case PhantomTextBox.ActionAfterSave.MoveUp: - Move(this, NavigationDirection.Up); + GetNext(this, NavigationDirection.Up); break; case PhantomTextBox.ActionAfterSave.MoveDown: - Move(this, NavigationDirection.Down); + GetNext(this, NavigationDirection.Down); break; case PhantomTextBox.ActionAfterSave.MoveNext: - Move(this, NavigationDirection.Next); + GetNext(this, NavigationDirection.Next); break; default: throw new ArgumentOutOfRangeException(nameof(action), action, null); } } - }, UseFallbackUnicodeFont(initialText) ? unicodeFallback : null); + }); } } @@ -502,7 +508,7 @@ private void UpdateKeyBindings() /*** * This is KeyBinding that forwards the gesture to the focused TextBox first */ - private class BetterKeyBinding : KeyBinding, ICommand + public class BetterKeyBinding : KeyBinding, ICommand { public static readonly StyledProperty CustomCommandProperty = AvaloniaProperty.Register(nameof (CustomCommand)); @@ -511,28 +517,52 @@ public ICommand CustomCommand get => GetValue(CustomCommandProperty); set => SetValue(CustomCommandProperty, value); } - + public BetterKeyBinding() { - Command = this; + SetCurrentValue(CommandProperty, this); + } + + public static TopLevel? GetTopLevel() + { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + return desktop.MainWindow; + } + if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime viewApp) + { + var visualRoot = viewApp.MainView?.GetVisualRoot(); + return visualRoot as TopLevel; + } + return null; } public bool CanExecute(object? parameter) { - if (FocusManager.Instance!.Current is TextBox tb) - return true; + var focusManager = GetTopLevel()?.FocusManager; + var currentAsTextBox = focusManager?.GetFocusedElement() as TextBox; + var currentAsTextEditor = focusManager?.GetFocusedElement() as TextEditor; + var currentAsTextArea = focusManager?.GetFocusedElement() as TextArea; + if (currentAsTextBox != null || currentAsTextEditor != null || currentAsTextArea != null) + return true; return CustomCommand.CanExecute(parameter); } public void Execute(object? parameter) { - if (FocusManager.Instance!.Current is TextBox tb) + var focusManager = GetTopLevel()?.FocusManager; + var currentAsTextBox = focusManager?.GetFocusedElement() as TextBox; + var currentAsTextEditor = focusManager?.GetFocusedElement() as TextEditor; + var currentAsTextArea = focusManager?.GetFocusedElement() as TextArea; + if (currentAsTextBox != null || currentAsTextEditor != null || currentAsTextArea != null) { - var ev = Activator.CreateInstance(); - ev.Key = Gesture.Key; - ev.KeyModifiers = Gesture.KeyModifiers; - ev.RoutedEvent = InputElement.KeyDownEvent; - tb.RaiseEvent(ev); + var ev = new KeyEventArgs() + { + Key = Gesture.Key, + KeyModifiers = Gesture.KeyModifiers, + RoutedEvent = InputElement.KeyDownEvent + }; + ((Control?)currentAsTextBox ?? (Control?)currentAsTextEditor ?? currentAsTextArea)!.RaiseEvent(ev); if (!ev.Handled && CanExecute(parameter)) CustomCommand.Execute(parameter); } diff --git a/AvaloniaStyles/Controls/RecyclableViewList.cs b/AvaloniaStyles/Controls/RecyclableViewList.cs index e2bb8aa75..2a6b94d9d 100644 --- a/AvaloniaStyles/Controls/RecyclableViewList.cs +++ b/AvaloniaStyles/Controls/RecyclableViewList.cs @@ -11,7 +11,7 @@ public class RecyclableViewList { private readonly Panel owner; private readonly bool behind; - private List controls = new(); + private List controls = new(); private int counter = 0; private IDataTemplate? template; @@ -27,14 +27,14 @@ public void Reset(IDataTemplate? template) counter = 0; } - public bool TryGetNext(object context, out IControl control) + public bool TryGetNext(object context, out Control control) { control = null!; if (template == null) return false; if (counter >= controls.Count) { - control = template!.Build(null!); + control = template!.Build(null!)!; controls.Add(control); control.DataContext = context; if (behind) @@ -54,7 +54,7 @@ public bool TryGetNext(object context, out IControl control) controls[counter] = found; controls[i] = atCounter; - + ++counter; control = found; return true; @@ -64,6 +64,7 @@ public bool TryGetNext(object context, out IControl control) } control = controls[counter++]; + control.DataContext = null; control.DataContext = context; control.IsVisible = true; control.InvalidateMeasure(); @@ -71,7 +72,7 @@ public bool TryGetNext(object context, out IControl control) return true; } - public IControl GetNext(object context) + public Control GetNext(object context) { if (!TryGetNext(context, out var control)) throw new Exception("Template is null!"); @@ -89,4 +90,4 @@ public void Finish() template = null; } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/SettingItem.axaml b/AvaloniaStyles/Controls/SettingItem.axaml index cfaa558f5..0011c791c 100644 --- a/AvaloniaStyles/Controls/SettingItem.axaml +++ b/AvaloniaStyles/Controls/SettingItem.axaml @@ -5,13 +5,13 @@ - - - @@ -56,10 +56,10 @@ - - diff --git a/AvaloniaStyles/Controls/SettingItem.axaml.cs b/AvaloniaStyles/Controls/SettingItem.axaml.cs index 5fff2e1be..8d2041b9d 100644 --- a/AvaloniaStyles/Controls/SettingItem.axaml.cs +++ b/AvaloniaStyles/Controls/SettingItem.axaml.cs @@ -31,7 +31,7 @@ internal class SettingItemContentPresenter : ContentPresenter { protected override Size ArrangeOverride(Size finalSize) { - if (Child is TextBox || Child.HorizontalAlignment == HorizontalAlignment.Stretch) + if (Child is TextBox || Child != null && Child.HorizontalAlignment == HorizontalAlignment.Stretch) { if (HorizontalContentAlignment != HorizontalAlignment.Stretch) HorizontalContentAlignment = HorizontalAlignment.Stretch; diff --git a/AvaloniaStyles/Controls/StretchStackPanel.cs b/AvaloniaStyles/Controls/StretchStackPanel.cs index 3a4a311e5..c8c457756 100644 --- a/AvaloniaStyles/Controls/StretchStackPanel.cs +++ b/AvaloniaStyles/Controls/StretchStackPanel.cs @@ -14,7 +14,15 @@ public double Spacing get => GetValue(SpacingProperty); set => SetValue(SpacingProperty, value); } - + + public static readonly StyledProperty StretchProperty = AvaloniaProperty.Register(nameof(Stretch), true); + + public bool Stretch + { + get => GetValue(StretchProperty); + set => SetValue(StretchProperty, value); + } + protected override Size ArrangeOverride(Size finalSize) { Avalonia.Controls.Controls children = Children; @@ -22,7 +30,7 @@ protected override Size ArrangeOverride(Size finalSize) int index = 0; for (int count = children.Count; index < count; ++index) { - IControl control = children[index]; + Control control = children[index]; if (control == null) continue; @@ -33,11 +41,13 @@ protected override Size ArrangeOverride(Size finalSize) double singleWidth = (finalSize.Width - Spacing * Math.Max(0, visibleChildrenCount - 1)) / visibleChildrenCount; double x = 0; + double widthLeft = finalSize.Width; + bool stretch = Stretch; index = 0; for (int count = children.Count; index < count; ++index) { - IControl control = children[index]; + Control control = children[index]; if (control == null) continue; @@ -45,9 +55,11 @@ protected override Size ArrangeOverride(Size finalSize) if (!isVisible) continue; - - control.Arrange(new Rect(x, finalSize.Height / 2 - control.DesiredSize.Height/2, singleWidth, control.DesiredSize.Height)); - x += singleWidth + Spacing; + + var width = stretch ? singleWidth : Math.Clamp(control.DesiredSize.Width, 0, widthLeft); + control.Arrange(new Rect(x, finalSize.Height / 2 - control.DesiredSize.Height/2, width, control.DesiredSize.Height)); + x += width + Spacing; + widthLeft -= width + Spacing; } return finalSize; @@ -65,7 +77,7 @@ protected override Size MeasureOverride(Size availableSize) int index = 0; for (int count = children.Count; index < count; ++index) { - IControl control = children[index]; + Control control = children[index]; if (control != null) { bool isVisible = control.IsVisible; diff --git a/AvaloniaStyles/Controls/StretchWrapPanel.cs b/AvaloniaStyles/Controls/StretchWrapPanel.cs index ba0d3464c..4fefa37e6 100644 --- a/AvaloniaStyles/Controls/StretchWrapPanel.cs +++ b/AvaloniaStyles/Controls/StretchWrapPanel.cs @@ -35,9 +35,9 @@ protected override Size MeasureOverride(Size availableSize) for (var i = 0; i < visualCount; i++) { - IVisual visual = visualChildren[i]; + Visual visual = visualChildren[i]; - if (visual is not ILayoutable layoutable) + if (visual is not Layoutable layoutable) continue; layoutable.Measure(availableSize.WithWidth(Math.Max(availableSize.Width, 100))); @@ -87,9 +87,9 @@ protected override Size ArrangeOverride(Size finalSize) for (var i = 0; i < visualCount; i++) { - IVisual visual = visualChildren[i]; + Visual visual = visualChildren[i]; - if (visual is ILayoutable layoutable) + if (visual is Layoutable layoutable) { StyledElement? styledElement = layoutable as StyledElement; if (styledElement == null) diff --git a/AvaloniaStyles/Controls/ToolbarControl.axaml b/AvaloniaStyles/Controls/ToolbarControl.axaml index c21ebe691..f21e074ae 100644 --- a/AvaloniaStyles/Controls/ToolbarControl.axaml +++ b/AvaloniaStyles/Controls/ToolbarControl.axaml @@ -1,69 +1,98 @@ - - - - - - - + + diff --git a/AvaloniaStyles/Controls/ToolbarControl.axaml.cs b/AvaloniaStyles/Controls/ToolbarControl.axaml.cs deleted file mode 100644 index c891c15f7..000000000 --- a/AvaloniaStyles/Controls/ToolbarControl.axaml.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.LogicalTree; -using Avalonia.Metadata; -using Avalonia.VisualTree; - -namespace AvaloniaStyles.Controls; - -public class ToolbarControl : TemplatedControl, IPanel -{ - public ToolbarControl() => this.Children.CollectionChanged += new NotifyCollectionChangedEventHandler(this.ChildrenChanged); - - public static readonly StyledProperty IsOverflowProperty = AvaloniaProperty.Register(nameof(IsOverflow)); - - public bool IsOverflow - { - get => GetValue(IsOverflowProperty); - set => SetValue(IsOverflowProperty, value); - } - - private Panel? childrenHost; - - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - childrenHost = e.NameScope.Find("PART_ChildrenHost"); - foreach (var child in Children) - childrenHost.Children.Add(child); - } - - private void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - List list = e.NewItems!.OfType().ToList(); - if (childrenHost != null) - { - foreach (Control control in list) - childrenHost.Children.Add(control); - } - break; - case NotifyCollectionChangedAction.Remove: - List oldList = e.OldItems!.OfType().ToList(); - if (childrenHost != null) - { - foreach (Control control in oldList) - childrenHost.Children.Remove(control); - } - break; - case NotifyCollectionChangedAction.Replace: - for (int index1 = 0; index1 < e.OldItems!.Count; ++index1) - { - int index2 = index1 + e.OldStartingIndex; - IControl? newItem = (IControl?) e.NewItems![index1]; - if (childrenHost != null) - childrenHost.Children[index2] = newItem; - } - break; - case NotifyCollectionChangedAction.Move: - if (childrenHost != null) - { - childrenHost.Children.MoveRange(e.OldStartingIndex, e.OldItems!.Count, e.NewStartingIndex); - } - break; - case NotifyCollectionChangedAction.Reset: - throw new NotSupportedException(); - } - } - - [Content] - public Avalonia.Controls.Controls Children { get; } = new Avalonia.Controls.Controls(); -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/ToolbarItemsControl.cs b/AvaloniaStyles/Controls/ToolbarItemsControl.cs index 505784d2e..1c88091a1 100644 --- a/AvaloniaStyles/Controls/ToolbarItemsControl.cs +++ b/AvaloniaStyles/Controls/ToolbarItemsControl.cs @@ -1,8 +1,75 @@ +using System.Collections.Specialized; +using System.Linq; +using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Metadata; namespace AvaloniaStyles.Controls; public class ToolbarItemsControl : ItemsControl { + public static readonly StyledProperty IsOverflowProperty = AvaloniaProperty.Register(nameof(IsOverflow)); + public bool IsOverflow + { + get => GetValue(IsOverflowProperty); + set => SetValue(IsOverflowProperty, value); + } +} + +public class ToolbarControl : TemplatedControl +{ + public static readonly StyledProperty IsOverflowProperty = AvaloniaProperty.Register(nameof(IsOverflow)); + + public bool IsOverflow + { + get => GetValue(IsOverflowProperty); + set => SetValue(IsOverflowProperty, value); + } + + private Panel? panel; + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + panel = e.NameScope.Get("PART_Panel"); + panel.Children.AddRange(Children); + } + + public ToolbarControl() => Children.CollectionChanged += ChildrenChanged; + + private void ChildrenChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (panel == null) + return; + + if (e.Action == NotifyCollectionChangedAction.Add) + { + panel.Children.AddRange(e.NewItems!.OfType()); + } + else if (e.Action == NotifyCollectionChangedAction.Remove) + { + panel.Children.RemoveAll(e.OldItems!.OfType()); + } + else if (e.Action == NotifyCollectionChangedAction.Replace) + { + for (int index1 = 0; index1 < e.OldItems!.Count; ++index1) + { + int index2 = index1 + e.OldStartingIndex; + Control? newItem = (Control?) e.NewItems![index1]; + panel.Children[index2] = newItem!; + } + } + else + { + if (e.Action != NotifyCollectionChangedAction.Reset) + return; + panel.Children.Clear(); + panel.Children.AddRange(Children); + } + } + + [Content] + public Avalonia.Controls.Controls Children { get; } = new(); } \ No newline at end of file diff --git a/AvaloniaStyles/Controls/ToolbarPanel.cs b/AvaloniaStyles/Controls/ToolbarPanel.cs index e5e809796..6f4402e74 100644 --- a/AvaloniaStyles/Controls/ToolbarPanel.cs +++ b/AvaloniaStyles/Controls/ToolbarPanel.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.Reflection; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Layout; using Avalonia.VisualTree; +using WDE.Common; namespace AvaloniaStyles.Controls { @@ -15,7 +17,7 @@ public class ToolbarPanel : Panel public static readonly StyledProperty WrapOnOverflowProperty = AvaloniaProperty.Register(nameof(WrapOnOverflow)); public static readonly StyledProperty SpacingProperty = AvaloniaProperty.Register(nameof(Spacing), 4); - private List _overflowControls = new List(); + private List _overflowControls = new List(); public Panel? OutOfBoundsPanel { @@ -41,8 +43,17 @@ public double Spacing set => SetValue(SpacingProperty, value); } + delegate void InvalidateStylesType(StyledElement element, bool recurse); + private static InvalidateStylesType? invalidateStyle; + static ToolbarPanel() { + var invalidateStyleMethod = typeof(StyledElement).GetMethod("InvalidateStyles", BindingFlags.Instance | BindingFlags.NonPublic); + if (invalidateStyleMethod != null) + invalidateStyle = (InvalidateStylesType)Delegate.CreateDelegate(typeof(InvalidateStylesType), invalidateStyleMethod); + else + LOG.LogCritical("Failed to find InvalidateStyles method (probably due to Avalonia version update)!!!"); + OutOfBoundsPanelProperty.Changed.AddClassHandler((panel, e) => panel.OnChangedPanel(e)); AffectsMeasure(SpacingProperty); AffectsArrange(SpacingProperty); @@ -61,6 +72,8 @@ private void NewPanelOnAttachedToVisualTree(object? sender, VisualTreeAttachment foreach (var child in _overflowControls) { OutOfBoundsPanel!.Children.Insert(0, child); + // @todo ava11: is that necessary? + child.ApplyStyling(); } _overflowControls.Clear(); } @@ -99,6 +112,7 @@ protected override Size MeasureOverride(Size availableSize) int rows = 1; var children = Children; bool any = false; + for (int i = 0, count = children.Count; i < count; ++i) { var child = children[i]; @@ -245,8 +259,8 @@ protected override Size ArrangeOverride(Size finalSize) rcChild = rcChild.WithHeight(Math.Max(finalSize.Height, child.DesiredSize.Height)); // we want to stretch only content presenters, not buttons // if it doesn't work for future toolbars, it can be changed - if (child.HorizontalAlignment == HorizontalAlignment.Stretch && child is ContentPresenter cp && - cp.Child is not Button) + if (child.HorizontalAlignment == HorizontalAlignment.Stretch && + (child is ContentPresenter { Child: not Button } || (child is ContentControl))) { previousChildSize = child.DesiredSize.Width + Math.Max(0, leftSpace); rcChild = rcChild.WithWidth(previousChildSize); @@ -274,7 +288,7 @@ protected override Size ArrangeOverride(Size finalSize) { var c = children[^1]; Children.RemoveAt(Children.Count - 1); - if (((IVisual)panel).IsAttachedToVisualTree) + if (panel.IsAttachedToVisualTree()) { panel.Children.Insert(0, c); ((ISetInheritanceParent)c).SetParent(this); @@ -282,7 +296,7 @@ protected override Size ArrangeOverride(Size finalSize) else _overflowControls.Add(c); } - IsOverflow = true; + SetCurrentValue(IsOverflowProperty, true); return finalSize; } } @@ -293,7 +307,7 @@ protected override Size ArrangeOverride(Size finalSize) { if (leftSpace > 0) { - IControl? child = null; + Control? child = null; if (_overflowControls.Count > 0) { child = _overflowControls[^1]; @@ -312,10 +326,17 @@ protected override Size ArrangeOverride(Size finalSize) else OutOfBoundsPanel.Children.RemoveAt(0); Children.Add(child); + // it really sucks I have to call InvalidateStyles via reflection, but without this + // buttons style bug in Solution Explorer in the following case + // shrink the toolbar to overflow buttons + // open the flyout + // expand the toolbar to show all buttons - now the buttons are not styled + invalidateStyle?.Invoke(child, true); + child.ApplyStyling(); } } } - IsOverflow = OutOfBoundsPanel.Children.Count > 0 || _overflowControls.Count > 0; + SetCurrentValue(IsOverflowProperty, OutOfBoundsPanel.Children.Count > 0 || _overflowControls.Count > 0); } return finalSize; @@ -370,7 +391,7 @@ private Size ArrangeWithWrapOverride(Size finalSize) } internal virtual void ArrangeChild( - IControl child, + Control child, Rect rect, Size panelSize) { @@ -381,4 +402,4 @@ internal virtual void ArrangeChild( public class ToolbarSpacer : Control { } -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/ToolsTabControl.cs b/AvaloniaStyles/Controls/ToolsTabControl.cs index c5efa542e..8b1378917 100644 --- a/AvaloniaStyles/Controls/ToolsTabControl.cs +++ b/AvaloniaStyles/Controls/ToolsTabControl.cs @@ -1,128 +1 @@ -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Generators; -using Avalonia.Controls.Presenters; -using Avalonia.Controls.Templates; -using Avalonia.Styling; -namespace AvaloniaStyles.Controls -{ - public class ToolsTabControl : TabControl, IStyleable - { - public static readonly AvaloniaProperty AttachedViewProperty = - AvaloniaProperty.RegisterAttached("AttachedView"); - - public static IControl? GetAttachedView(TabItem control) => (IControl?) control.GetValue(AttachedViewProperty); - - public static void SetAttachedView(TabItem control, IControl? value) => - control.SetValue(AttachedViewProperty, value); - - - public static readonly AvaloniaProperty ToolTitleProperty = - AvaloniaProperty.RegisterAttached("ToolTitle"); - public static string? GetToolTitle(TabItem control) => (string?) control.GetValue(ToolTitleProperty); - public static void SetToolTitle(TabItem control, string value) => - control.SetValue(ToolTitleProperty, value); - - - public static readonly StyledProperty ActiveViewProperty = - AvaloniaProperty.Register(nameof(ActiveView)); - - public IControl? ActiveView - { - get => GetValue(ActiveViewProperty); - internal set => SetValue(ActiveViewProperty, value); - } - - internal IContentPresenter? ContentPart { get; private set; } - private static readonly FuncTemplate DefaultPanel = - new FuncTemplate(() => new StackPanel(){Name = "ToolsList"}); - - static ToolsTabControl() - { - ItemsPanelProperty.OverrideDefaultValue(DefaultPanel); - - SelectedContentProperty.Changed.AddClassHandler((viewModelItemsControl, e) => - { - if (viewModelItemsControl.SelectedItem != null && - viewModelItemsControl.itemsToViews.TryGetValue(viewModelItemsControl.SelectedItem, out var view)) - viewModelItemsControl.ActiveView = view; - else - viewModelItemsControl.ActiveView = null; - if (viewModelItemsControl.ContentPart != null) - viewModelItemsControl.ContentPart.DataContext = viewModelItemsControl.SelectedItem; - }); - } - - protected override bool RegisterContentPresenter(IContentPresenter presenter) - { - base.RegisterContentPresenter(presenter); - if (presenter.Name == "PART_SelectedContentHost") - { - ContentPart = presenter; - return true; - } - - return false; - } - - protected override void OnContainersMaterialized(ItemContainerEventArgs e) - { - base.OnContainersMaterialized(e); - - foreach (var container in e.Containers) - { - if (container.Item != null && itemsToViews.TryGetValue(container.Item, out var vieww)) - SetAttachedView((TabItem)container.ContainerControl, vieww as IControl); - } - } - - private Dictionary itemsToViews = new(); - - protected override void ItemsChanged(AvaloniaPropertyChangedEventArgs e) - { - if (e.NewValue != null) - GenerateContent((IList)e.NewValue); - base.ItemsChanged(e); - } - - protected override void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - switch (e.Action) - { - case NotifyCollectionChangedAction.Add: - GenerateContent(e.NewItems!); - break; - - case NotifyCollectionChangedAction.Remove: - FreeContent(e.OldItems!); - break; - } - - base.ItemsCollectionChanged(sender, e); - } - - private void FreeContent(IList eOldItems) - { - foreach (var o in eOldItems) - itemsToViews.Remove(o); - } - - private void GenerateContent(IList eNewItems) - { - foreach (var o in eNewItems) - { - IControl view = GenerateView(o); - itemsToViews[o] = view; - } - } - - protected virtual IControl GenerateView(object viewModel) - { - return new TextBlock() {Text = viewModel.ToString()}; - } - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Controls/TwoColumnsPanel.cs b/AvaloniaStyles/Controls/TwoColumnsPanel.cs index f8ff64d86..daa8de98d 100644 --- a/AvaloniaStyles/Controls/TwoColumnsPanel.cs +++ b/AvaloniaStyles/Controls/TwoColumnsPanel.cs @@ -44,12 +44,12 @@ static TwoColumnsPanel() VerticalAlignmentProperty.OverrideDefaultValue(VerticalAlignment.Top); } - private IEnumerable<(IControl left, IControl? right)> GetChildren() + private IEnumerable<(Control left, Control? right)> GetChildren() { for (var index = 0; index < Children.Count; index++) { - IControl left; - IControl? right = null; + Control left; + Control? right = null; left = Children[index]; if (left.IsSet(ColumnSpanProperty)) diff --git a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridCheckBox.cs b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridCheckBox.cs index 41d7ea84f..d950e1a79 100644 --- a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridCheckBox.cs +++ b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridCheckBox.cs @@ -8,7 +8,7 @@ namespace AvaloniaStyles.Controls; -public class VirtualizedGridCheckBox : CheckBox, IStyleable +public class VirtualizedGridCheckBox : CheckBox { private IMultiIndexContainer? checkedIndices; public static readonly DirectProperty CheckedIndicesProperty = @@ -30,7 +30,7 @@ public int Index set => SetAndRaise(IndexProperty, ref index, value); } - Type IStyleable.StyleKey => typeof(CheckBox); + protected override Type StyleKeyOverride => typeof(CheckBox); static VirtualizedGridCheckBox() { diff --git a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridView.cs b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridView.cs index e7cb909a6..5e3f66ffe 100644 --- a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridView.cs +++ b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridView.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Linq; using Avalonia; using Avalonia.Collections; @@ -9,6 +10,7 @@ using Avalonia.Input; using Avalonia.Input.Platform; using Avalonia.Interactivity; +using Avalonia.Utilities; using Avalonia.VisualTree; using DynamicData; using WDE.Common.Collections; @@ -46,12 +48,18 @@ public class VirtualizedGridView : TemplatedControl public static readonly RoutedEvent ColumnWidthChangedEvent = RoutedEvent.Register(nameof(ColumnWidthChanged), RoutingStrategies.Bubble); + static VirtualizedGridView() + { + FocusableProperty.OverrideDefaultValue(true); + } + public event EventHandler ColumnWidthChanged { add => AddHandler(ColumnWidthChangedEvent, value); remove => RemoveHandler(ColumnWidthChangedEvent, value); } - + +#pragma warning disable AVP1030 public int? FocusedIndex { get @@ -63,6 +71,8 @@ public int? FocusedIndex } set => SetValue(FocusedIndexProperty, value); } +#pragma warning restore AVP1030 + public double ItemHeight { get => itemHeight; @@ -107,6 +117,8 @@ public IEnumerable Columns private VirtualizedGridViewItemPresenter? children; private Grid? header; + private ScrollViewer? headerScroll; + private ScrollViewer? contentScroll; public VirtualizedGridViewItemPresenter? ItemPresenter => children; @@ -119,7 +131,7 @@ protected override void OnKeyDown(KeyEventArgs e) if (e.Key is Key.Up or Key.Down) { var rangeModifier = e.KeyModifiers.HasFlagFast(KeyModifiers.Shift); - var toggleModifier = e.KeyModifiers.HasFlagFast(AvaloniaLocator.Current.GetRequiredService().CommandModifiers); + var toggleModifier = e.KeyModifiers.HasFlagFast(RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? KeyModifiers.Meta : KeyModifiers.Control); int index; if (e.Key == Key.Up) @@ -142,7 +154,7 @@ protected override void OnKeyDown(KeyEventArgs e) protected ListBoxItem? GetContainerFromEventSource(object? eventSource) { - for (var current = eventSource as IVisual; current != null; current = current.GetVisualParent()) + for (var current = eventSource as Visual; current != null; current = current.GetVisualParent()) { if (current is ListBoxItem lbi) { @@ -168,11 +180,21 @@ public IEnumerable GetColumnsWidth() protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { - header = e.NameScope.Find("PART_header"); - children = e.NameScope.Find("PART_Children"); + if (headerScroll is not null) + headerScroll.ScrollChanged -= OnHeaderScroll; + if (contentScroll is not null) + contentScroll.ScrollChanged -= OnContentScroll; + + header = e.NameScope.Get("PART_header"); + children = e.NameScope.Get("PART_Children"); + headerScroll = e.NameScope.Get("PART_HeaderScroll"); + contentScroll = e.NameScope.Get("PART_ContentScroll"); header.ColumnDefinitions.Clear(); header.Children.Clear(); + + headerScroll.ScrollChanged += OnHeaderScroll; + contentScroll.ScrollChanged += OnContentScroll; VirtualizedGridViewItemPresenter.SetupGridColumns(columns, header, true, useCheckBoxes); @@ -207,6 +229,18 @@ void AddHeaderCell(string name) AddHeaderCell(column.Name); } + private void OnContentScroll(object? sender, ScrollChangedEventArgs e) + { + if (contentScroll is not null && headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X)) + headerScroll.Offset = headerScroll.Offset.WithX(contentScroll.Offset.X); + } + + private void OnHeaderScroll(object? sender, ScrollChangedEventArgs e) + { + if (contentScroll is not null && headerScroll is not null && !MathUtilities.IsZero(e.OffsetDelta.X)) + contentScroll.Offset = contentScroll.Offset.WithX(headerScroll.Offset.X); + } + private void ColumnsSizeChanged() { RaiseEvent(new RoutedEventArgs() @@ -272,7 +306,7 @@ private void UpdateSelectionFromIndex(bool rangeModifier, bool toggleModifier, i for (int i = index; i <= oldFocusedIndex; ++i) selection.Add(i); } - FocusedIndex = index; + SetCurrentValue(FocusedIndexProperty, index); } else { @@ -280,7 +314,7 @@ private void UpdateSelectionFromIndex(bool rangeModifier, bool toggleModifier, i selection.Remove(index); else selection.Add(index); - FocusedIndex = index; + SetCurrentValue(FocusedIndexProperty, index); } } @@ -299,7 +333,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) e.Source, true, e.KeyModifiers.HasFlagFast(KeyModifiers.Shift), - e.KeyModifiers.HasFlagFast(AvaloniaLocator.Current.GetRequiredService().CommandModifiers), + e.KeyModifiers.HasFlagFast(RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? KeyModifiers.Meta : KeyModifiers.Control), point.Properties.IsRightButtonPressed); } } @@ -307,4 +341,4 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) private ScrollViewer? ScrollViewer => this.FindDescendantOfType(); -} \ No newline at end of file +} diff --git a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewItemPresenter.cs b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewItemPresenter.cs index 54ee845b6..51d5e50ba 100644 --- a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewItemPresenter.cs +++ b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewItemPresenter.cs @@ -8,6 +8,7 @@ using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; using Avalonia.Data; +using Avalonia.ReactiveUI; using Avalonia.Threading; using Avalonia.VisualTree; using WDE.Common.Collections; @@ -64,10 +65,10 @@ public VirtualizedGridViewItemPresenter() foreach (var column in Columns) { - IControl control; + Control control; if (column.DataTemplate is { } dt) { - control = dt.Build(column); + control = dt.Build(column) ?? new TextBlock(){Text = "Error: data template for column returned null control"}; } else if (column.Checkable) { @@ -181,7 +182,8 @@ public IIndexedCollection? Items get => items; set => SetAndRaise(ItemsProperty, ref items, value); } - + + #pragma warning disable AVP1030 public int? FocusedIndex { get @@ -193,6 +195,7 @@ public int? FocusedIndex } set => SetValue(FocusedIndexProperty, value); } + #pragma warning restore AVP1030 public IMultiIndexContainer Selection { diff --git a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewStyle.axaml b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewStyle.axaml index 4ce17188f..86f87e77b 100644 --- a/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewStyle.axaml +++ b/AvaloniaStyles/Controls/VirtualizedGridViewControl/VirtualizedGridViewStyle.axaml @@ -9,7 +9,7 @@ - - - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/BigSur/CheckBox.xaml b/AvaloniaStyles/Styles/BigSur/CheckBox.xaml index 0f5b4ceb8..aa19ac30a 100644 --- a/AvaloniaStyles/Styles/BigSur/CheckBox.xaml +++ b/AvaloniaStyles/Styles/BigSur/CheckBox.xaml @@ -36,7 +36,7 @@ diff --git a/AvaloniaStyles/Styles/BigSur/ContextMenu.xaml b/AvaloniaStyles/Styles/BigSur/ContextMenu.xaml index 232393cbb..d8738993b 100644 --- a/AvaloniaStyles/Styles/BigSur/ContextMenu.xaml +++ b/AvaloniaStyles/Styles/BigSur/ContextMenu.xaml @@ -3,8 +3,8 @@ - - + + diff --git a/AvaloniaStyles/Styles/BigSur/GroupingListBox.axaml b/AvaloniaStyles/Styles/BigSur/GroupingListBox.axaml index d3b3802e3..4844447e3 100644 --- a/AvaloniaStyles/Styles/BigSur/GroupingListBox.axaml +++ b/AvaloniaStyles/Styles/BigSur/GroupingListBox.axaml @@ -30,7 +30,7 @@ - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Catalina/CheckBox.xaml b/AvaloniaStyles/Styles/Catalina/CheckBox.xaml index 6e092b9a8..ad3a799c6 100644 --- a/AvaloniaStyles/Styles/Catalina/CheckBox.xaml +++ b/AvaloniaStyles/Styles/Catalina/CheckBox.xaml @@ -36,7 +36,7 @@ diff --git a/AvaloniaStyles/Styles/Catalina/ContextMenu.xaml b/AvaloniaStyles/Styles/Catalina/ContextMenu.xaml index a9b98a24d..69b6ad9ff 100644 --- a/AvaloniaStyles/Styles/Catalina/ContextMenu.xaml +++ b/AvaloniaStyles/Styles/Catalina/ContextMenu.xaml @@ -3,8 +3,8 @@ - - + + diff --git a/AvaloniaStyles/Styles/Catalina/GroupingListBox.axaml b/AvaloniaStyles/Styles/Catalina/GroupingListBox.axaml index d3b3802e3..4844447e3 100644 --- a/AvaloniaStyles/Styles/Catalina/GroupingListBox.axaml +++ b/AvaloniaStyles/Styles/Catalina/GroupingListBox.axaml @@ -30,7 +30,7 @@ + + - + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/ColorsDark.xaml b/AvaloniaStyles/Styles/Windows10/ColorsDark.xaml deleted file mode 100644 index c9d1f2ab9..000000000 --- a/AvaloniaStyles/Styles/Windows10/ColorsDark.xaml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 7,5,7,7 - 8,5,8,6 - 0.5 - 0.5 - - - - - - - - - - - - - - - - - - - - - #007ACC - #1C97EA - #52B0EF - #F0F0F0 - #007ACC - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AvaloniaStyles/Styles/Windows10/ColorsLight.xaml b/AvaloniaStyles/Styles/Windows10/ColorsLight.axaml similarity index 61% rename from AvaloniaStyles/Styles/Windows10/ColorsLight.xaml rename to AvaloniaStyles/Styles/Windows10/ColorsLight.axaml index b391beb26..a20b7f38b 100644 --- a/AvaloniaStyles/Styles/Windows10/ColorsLight.xaml +++ b/AvaloniaStyles/Styles/Windows10/ColorsLight.axaml @@ -1,6 +1,9 @@ + + + @@ -11,9 +14,9 @@ - + - + @@ -129,11 +132,49 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -42,18 +42,18 @@ diff --git a/AvaloniaStyles/Styles/Windows10/Dock.axaml b/AvaloniaStyles/Styles/Windows10/Dock.axaml new file mode 100644 index 000000000..fa805dbb3 --- /dev/null +++ b/AvaloniaStyles/Styles/Windows10/Dock.axaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/AvaloniaStyles/Styles/Windows10/DockLight.axaml b/AvaloniaStyles/Styles/Windows10/DockLight.axaml index 773195736..05feb0c8b 100644 --- a/AvaloniaStyles/Styles/Windows10/DockLight.axaml +++ b/AvaloniaStyles/Styles/Windows10/DockLight.axaml @@ -14,26 +14,26 @@ - - - - - - @@ -43,7 +43,7 @@ - diff --git a/AvaloniaStyles/Styles/Windows10/ListBox.xaml b/AvaloniaStyles/Styles/Windows10/ListBox.axaml similarity index 100% rename from AvaloniaStyles/Styles/Windows10/ListBox.xaml rename to AvaloniaStyles/Styles/Windows10/ListBox.axaml diff --git a/AvaloniaStyles/Styles/Windows10/NativeMenuBar.xaml b/AvaloniaStyles/Styles/Windows10/NativeMenuBar.xaml deleted file mode 100644 index eddad65a2..000000000 --- a/AvaloniaStyles/Styles/Windows10/NativeMenuBar.xaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/SideBar.xaml b/AvaloniaStyles/Styles/Windows10/SideBar.axaml similarity index 100% rename from AvaloniaStyles/Styles/Windows10/SideBar.xaml rename to AvaloniaStyles/Styles/Windows10/SideBar.axaml diff --git a/AvaloniaStyles/Styles/Windows10/StatusBar.xaml b/AvaloniaStyles/Styles/Windows10/StatusBar.axaml similarity index 88% rename from AvaloniaStyles/Styles/Windows10/StatusBar.xaml rename to AvaloniaStyles/Styles/Windows10/StatusBar.axaml index 4fa24de30..4e7238075 100644 --- a/AvaloniaStyles/Styles/Windows10/StatusBar.xaml +++ b/AvaloniaStyles/Styles/Windows10/StatusBar.axaml @@ -20,7 +20,7 @@ \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/Style.xaml b/AvaloniaStyles/Styles/Windows10/Style.axaml similarity index 70% rename from AvaloniaStyles/Styles/Windows10/Style.xaml rename to AvaloniaStyles/Styles/Windows10/Style.axaml index 84d6e4bb2..c485a6e30 100644 --- a/AvaloniaStyles/Styles/Windows10/Style.xaml +++ b/AvaloniaStyles/Styles/Windows10/Style.axaml @@ -3,10 +3,16 @@ xmlns:system="clr-namespace:System;assembly=System.Runtime"> @@ -15,17 +21,15 @@ - - - + - + @@ -36,10 +40,11 @@ - - - + + + + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/TabControl.axaml b/AvaloniaStyles/Styles/Windows10/TabControl.axaml index aee305e0f..b7d50664e 100644 --- a/AvaloniaStyles/Styles/Windows10/TabControl.axaml +++ b/AvaloniaStyles/Styles/Windows10/TabControl.axaml @@ -23,9 +23,7 @@ @@ -79,9 +77,9 @@ Content="{TemplateBinding Header}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" - TextBlock.FontFamily="{TemplateBinding FontFamily}" - TextBlock.FontSize="{TemplateBinding FontSize}" - TextBlock.FontWeight="{TemplateBinding FontWeight}" /> + TextElement.FontFamily="{TemplateBinding FontFamily}" + TextElement.FontSize="{TemplateBinding FontSize}" + TextElement.FontWeight="{TemplateBinding FontWeight}" /> @@ -102,7 +100,7 @@ @@ -139,7 +137,7 @@ @@ -152,4 +150,9 @@ - \ No newline at end of file + + + + diff --git a/AvaloniaStyles/Styles/Windows10/TabStrip.xaml b/AvaloniaStyles/Styles/Windows10/TabStrip.axaml similarity index 96% rename from AvaloniaStyles/Styles/Windows10/TabStrip.xaml rename to AvaloniaStyles/Styles/Windows10/TabStrip.axaml index a6d072cae..b4efc30ab 100644 --- a/AvaloniaStyles/Styles/Windows10/TabStrip.xaml +++ b/AvaloniaStyles/Styles/Windows10/TabStrip.axaml @@ -10,9 +10,7 @@ + ItemsPanel="{TemplateBinding ItemsPanel}" /> diff --git a/AvaloniaStyles/Styles/Windows10/ToolbarPanel.axaml b/AvaloniaStyles/Styles/Windows10/ToolbarPanel.axaml index 775c7c183..ab41fd19b 100644 --- a/AvaloniaStyles/Styles/Windows10/ToolbarPanel.axaml +++ b/AvaloniaStyles/Styles/Windows10/ToolbarPanel.axaml @@ -34,6 +34,10 @@ + @@ -41,7 +45,8 @@ - + + + @@ -69,6 +78,39 @@ + + + + + + + + + + + + @@ -96,29 +142,66 @@ + + + + + + + + + + - - - - - + - @@ -131,6 +214,7 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/TreeViewItem.axaml b/AvaloniaStyles/Styles/Windows10/TreeViewItem.axaml index 6ca4e4605..2b546abaf 100644 --- a/AvaloniaStyles/Styles/Windows10/TreeViewItem.axaml +++ b/AvaloniaStyles/Styles/Windows10/TreeViewItem.axaml @@ -6,16 +6,16 @@ - + - + - + 28 16 @@ -25,44 +25,4 @@ Left="True" x:Key="TreeViewItemLeftMarginConverter" /> - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/Window.axaml b/AvaloniaStyles/Styles/Windows10/Window.axaml new file mode 100644 index 000000000..ef6058247 --- /dev/null +++ b/AvaloniaStyles/Styles/Windows10/Window.axaml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AvaloniaStyles/Styles/Windows10/Window.xaml b/AvaloniaStyles/Styles/Windows10/Window.xaml deleted file mode 100644 index 81d4dbd7c..000000000 --- a/AvaloniaStyles/Styles/Windows10/Window.xaml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10/WindowMessageBox.axaml b/AvaloniaStyles/Styles/Windows10/WindowMessageBox.axaml new file mode 100644 index 000000000..054773d9a --- /dev/null +++ b/AvaloniaStyles/Styles/Windows10/WindowMessageBox.axaml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows10Dark.xaml b/AvaloniaStyles/Styles/Windows10Dark.axaml similarity index 74% rename from AvaloniaStyles/Styles/Windows10Dark.xaml rename to AvaloniaStyles/Styles/Windows10Dark.axaml index dde0312ff..e414db22d 100644 --- a/AvaloniaStyles/Styles/Windows10Dark.xaml +++ b/AvaloniaStyles/Styles/Windows10Dark.axaml @@ -1,6 +1,6 @@ - - - + + + diff --git a/AvaloniaStyles/Styles/Windows10Light.xaml b/AvaloniaStyles/Styles/Windows10Light.axaml similarity index 72% rename from AvaloniaStyles/Styles/Windows10Light.xaml rename to AvaloniaStyles/Styles/Windows10Light.axaml index 6297403cf..3169bf442 100644 --- a/AvaloniaStyles/Styles/Windows10Light.xaml +++ b/AvaloniaStyles/Styles/Windows10Light.axaml @@ -1,7 +1,8 @@ - - - + + + diff --git a/AvaloniaStyles/Styles/Windows10Light.cs b/AvaloniaStyles/Styles/Windows10Light.cs new file mode 100644 index 000000000..9ed579496 --- /dev/null +++ b/AvaloniaStyles/Styles/Windows10Light.cs @@ -0,0 +1,12 @@ +using System; +using Avalonia.Markup.Xaml; + +namespace AvaloniaStyles.Styles; + +public class Windows10Light : Avalonia.Styling.Styles +{ + public Windows10Light(IServiceProvider? sp = null) + { + AvaloniaXamlLoader.Load(sp, this); + } +} \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows11/Button.axaml b/AvaloniaStyles/Styles/Windows11/Button.axaml index b9bffc191..b50ace178 100644 --- a/AvaloniaStyles/Styles/Windows11/Button.axaml +++ b/AvaloniaStyles/Styles/Windows11/Button.axaml @@ -2,27 +2,29 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:AvaloniaStyles.Controls" xmlns:utils="clr-namespace:AvaloniaStyles.Utils"> - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows11/ColorsDark.xaml b/AvaloniaStyles/Styles/Windows11/ColorsDark.axaml similarity index 62% rename from AvaloniaStyles/Styles/Windows11/ColorsDark.xaml rename to AvaloniaStyles/Styles/Windows11/ColorsDark.axaml index 97f72cb83..8765a59e8 100644 --- a/AvaloniaStyles/Styles/Windows11/ColorsDark.xaml +++ b/AvaloniaStyles/Styles/Windows11/ColorsDark.axaml @@ -1,16 +1,16 @@ - + - - - + + + - + @@ -39,12 +39,12 @@ - - - - - - + + + + + + 0,0,0,1 @@ -71,17 +71,17 @@ #19FFFFFF #33FFFFFF - - - - + + + + - + diff --git a/AvaloniaStyles/Styles/Windows11/ColorsLight.xaml b/AvaloniaStyles/Styles/Windows11/ColorsLight.axaml similarity index 61% rename from AvaloniaStyles/Styles/Windows11/ColorsLight.xaml rename to AvaloniaStyles/Styles/Windows11/ColorsLight.axaml index 57c709f60..e7f918c7e 100644 --- a/AvaloniaStyles/Styles/Windows11/ColorsLight.xaml +++ b/AvaloniaStyles/Styles/Windows11/ColorsLight.axaml @@ -3,19 +3,19 @@ xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:styles="clr-namespace:AvaloniaStyles.Styles" xmlns:utils="clr-namespace:AvaloniaStyles.Utils"> - + - - - + + + - + - + @@ -37,8 +37,8 @@ #086FBF #74b9ff--> - - + + @@ -47,12 +47,12 @@ - - - - - - + + + + + + 0,0,0,1 @@ -68,11 +68,11 @@ #19000000 #33000000 - - - - + + + + @@ -90,6 +90,6 @@ - + diff --git a/AvaloniaStyles/Styles/Windows11/DockLight.axaml b/AvaloniaStyles/Styles/Windows11/DockLight.axaml index e23b05094..964f58d47 100644 --- a/AvaloniaStyles/Styles/Windows11/DockLight.axaml +++ b/AvaloniaStyles/Styles/Windows11/DockLight.axaml @@ -2,9 +2,9 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:idc="clr-namespace:Dock.Avalonia.Controls;assembly=Dock.Avalonia"> - - - + + + - - - - - - @@ -48,11 +48,11 @@ - - diff --git a/AvaloniaStyles/Styles/Windows11/NativeMenuBar.xaml b/AvaloniaStyles/Styles/Windows11/NativeMenuBar.xaml deleted file mode 100644 index c72433dca..000000000 --- a/AvaloniaStyles/Styles/Windows11/NativeMenuBar.xaml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows11/Style.xaml b/AvaloniaStyles/Styles/Windows11/Style.axaml similarity index 71% rename from AvaloniaStyles/Styles/Windows11/Style.xaml rename to AvaloniaStyles/Styles/Windows11/Style.axaml index 6cf7c5f48..a60b95a79 100644 --- a/AvaloniaStyles/Styles/Windows11/Style.xaml +++ b/AvaloniaStyles/Styles/Windows11/Style.axaml @@ -3,10 +3,17 @@ xmlns:system="clr-namespace:System;assembly=System.Runtime"> @@ -15,18 +22,18 @@ - - - + + + + - - + - + @@ -37,15 +44,13 @@ - - - - + + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows11/TabControl.axaml b/AvaloniaStyles/Styles/Windows11/TabControl.axaml index 072e25565..6c30fb5f6 100644 --- a/AvaloniaStyles/Styles/Windows11/TabControl.axaml +++ b/AvaloniaStyles/Styles/Windows11/TabControl.axaml @@ -3,7 +3,7 @@ diff --git a/AvaloniaStyles/Styles/Windows11/TextBox.axaml b/AvaloniaStyles/Styles/Windows11/TextBox.axaml index f30ad9cd8..b4a0fcb78 100644 --- a/AvaloniaStyles/Styles/Windows11/TextBox.axaml +++ b/AvaloniaStyles/Styles/Windows11/TextBox.axaml @@ -3,136 +3,159 @@ xmlns:controls="clr-namespace:AvaloniaStyles.Controls" xmlns:utils="clr-namespace:AvaloniaStyles.Utils" xmlns:avaloniaEdit="https://github.com/avaloniaui/avaloniaedit"> - + - + - - - + + + - + - + - + - - - + - + + + + + + + + + + + + + + - - - - + + + + + + + \ No newline at end of file diff --git a/AvaloniaStyles/Styles/Windows11/Window.axaml b/AvaloniaStyles/Styles/Windows11/Window.axaml index 31f8d158a..fd16419c6 100644 --- a/AvaloniaStyles/Styles/Windows11/Window.axaml +++ b/AvaloniaStyles/Styles/Windows11/Window.axaml @@ -9,9 +9,9 @@ - - - + + + diff --git a/AvaloniaStyles/Styles/Windows11Dark.xaml b/AvaloniaStyles/Styles/Windows11Dark.axaml similarity index 74% rename from AvaloniaStyles/Styles/Windows11Dark.xaml rename to AvaloniaStyles/Styles/Windows11Dark.axaml index 36e8a8ef9..d4cc3fd7e 100644 --- a/AvaloniaStyles/Styles/Windows11Dark.xaml +++ b/AvaloniaStyles/Styles/Windows11Dark.axaml @@ -1,6 +1,6 @@ - - - + + + diff --git a/AvaloniaStyles/Styles/Windows11Light.xaml b/AvaloniaStyles/Styles/Windows11Light.axaml similarity index 79% rename from AvaloniaStyles/Styles/Windows11Light.xaml rename to AvaloniaStyles/Styles/Windows11Light.axaml index b2bf08d80..ffb0cfef9 100644 --- a/AvaloniaStyles/Styles/Windows11Light.xaml +++ b/AvaloniaStyles/Styles/Windows11Light.axaml @@ -1,7 +1,7 @@ - - - + + + diff --git a/AvaloniaStyles/SystemTheme.cs b/AvaloniaStyles/SystemTheme.cs index a6f0081e8..536e68274 100644 --- a/AvaloniaStyles/SystemTheme.cs +++ b/AvaloniaStyles/SystemTheme.cs @@ -1,7 +1,9 @@ using System; using System.Runtime.InteropServices; +using Avalonia; using Avalonia.Markup.Xaml.Styling; using Avalonia.Metadata; +using Avalonia.Styling; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "AvaloniaStyles.Controls")] @@ -73,6 +75,10 @@ public SystemThemeOptions Mode // || EffectiveTheme == SystemThemeOptions.MacOsCatalinaDark || // EffectiveTheme == SystemThemeOptions.MacOsBigSurDark; + Application.Current!.RequestedThemeVariant = EffectiveThemeIsDark + ? ThemeVariant.Dark + : ThemeVariant.Light; + switch (EffectiveTheme) { // case SystemThemeOptions.MacOsCatalinaLight: @@ -88,19 +94,21 @@ public SystemThemeOptions Mode // Source = new Uri("avares://AvaloniaStyles/Styles/MacOsBigSurDark.xaml", UriKind.Absolute); // break; case SystemThemeOptions.DarkWindows10: - Source = new Uri("avares://AvaloniaStyles/Styles/Windows10Dark.xaml", UriKind.Absolute); + Source = new Uri("avares://AvaloniaStyles/Styles/Windows10Dark.axaml", UriKind.Absolute); break; case SystemThemeOptions.LightWindows10: - Source = new Uri("avares://AvaloniaStyles/Styles/Windows10Light.xaml", UriKind.Absolute); + Source = new Uri("avares://AvaloniaStyles/Styles/Windows10Light.axaml", UriKind.Absolute); break; case SystemThemeOptions.DarkWindows11: - Source = new Uri("avares://AvaloniaStyles/Styles/Windows11Dark.xaml", UriKind.Absolute); + Source = new Uri("avares://AvaloniaStyles/Styles/Windows11Dark.axaml", UriKind.Absolute); break; case SystemThemeOptions.LightWindows11: - Source = new Uri("avares://AvaloniaStyles/Styles/Windows11Light.xaml", UriKind.Absolute); + Source = new Uri("avares://AvaloniaStyles/Styles/Windows11Light.axaml", UriKind.Absolute); break; } } } + + public static ThemeVariant EffectiveThemeVariant => EffectiveThemeIsDark ? ThemeVariant.Dark : ThemeVariant.Light; } } \ No newline at end of file diff --git a/AvaloniaStyles/Utils/HslColor.cs b/AvaloniaStyles/Utils/HslColor.cs index 01c936427..4f4898933 100644 --- a/AvaloniaStyles/Utils/HslColor.cs +++ b/AvaloniaStyles/Utils/HslColor.cs @@ -47,8 +47,11 @@ public Color ToRgba(double opacity = 1) return new Color((byte)(opacity * 255), (byte)result.X, (byte)result.Y, (byte)result.Z); } - public HslColor Scale(HslDiff scaler) + public HslColor Scale(HslDiff? scaler) { + if (scaler == null) + return this; + double l = L; if (scaler.L > 0.5) { diff --git a/AvaloniaStyles/Utils/SolidBrushTransition.cs b/AvaloniaStyles/Utils/SolidBrushTransition.cs deleted file mode 100644 index fee1c634d..000000000 --- a/AvaloniaStyles/Utils/SolidBrushTransition.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Reactive.Linq; -using Avalonia; -using Avalonia.Animation; -using Avalonia.Animation.Easings; -using Avalonia.Media; -using Avalonia.Reactive; -using Avalonia.Utilities; - -namespace AvaloniaStyles.Utils -{ - public class SolidBrushTransition : Transition - { - /// - public override IObservable DoTransition(IObservable progress, IBrush oldValue, - IBrush newValue) - { - return progress - .Select(p => - { - SolidColorBrush? old = oldValue as SolidColorBrush; - SolidColorBrush? nnew = newValue as SolidColorBrush; - if (old == null || nnew == null) - return newValue; - var f = Easing.Ease(p); - return new SolidColorBrush(new Color( - (byte)((nnew.Color.A - old.Color.A) * f + old.Color.A), - (byte)((nnew.Color.R - old.Color.R) * f + old.Color.R), - (byte)((nnew.Color.G - old.Color.G) * f + old.Color.G), - (byte)((nnew.Color.B - old.Color.B) * f + old.Color.B) - )); - }); - } - } - - // copy paste of Avalonia Transition class, because I do not know why original doesn't work here... - public abstract class Transition : AvaloniaObject, ITransition - { - private AvaloniaProperty? _prop; - - /// - /// Gets or sets the duration of the transition. - /// - public TimeSpan Duration { get; set; } - - /// - /// Gets or sets delay before starting the transition. - /// - public TimeSpan Delay { get; set; } = TimeSpan.Zero; - - /// - /// Gets the easing class to be used. - /// - public Easing Easing { get; set; } = new LinearEasing(); - - /// - public AvaloniaProperty? Property - { - get { return _prop; } - set - { - if (value == null) - return; - - if (!(value.PropertyType.IsAssignableFrom(typeof(T)))) - throw new InvalidCastException - ($"Invalid property type \"{typeof(T).Name}\" for this transition: {GetType().Name}."); - - _prop = value; - } - } - - /// - /// Apply interpolation to the property. - /// - public abstract IObservable DoTransition(IObservable progress, T oldValue, T newValue); - - /// - public virtual IDisposable Apply(Animatable control, IClock clock, object oldValue, object newValue) - { - var transition = DoTransition(new TransitionInstance(clock, Delay, Duration), (T) oldValue, (T) newValue); - return control.Bind((AvaloniaProperty) Property!, transition, Avalonia.Data.BindingPriority.Animation); - } - } - - internal class TransitionInstance : SingleSubscriberObservableBase - { - private IDisposable? _timerSubscription; - private TimeSpan _delay; - private TimeSpan _duration; - private readonly IClock _baseClock; - private IClock? _clock; - - public TransitionInstance(IClock clock, TimeSpan delay, TimeSpan duration) - { - clock = clock ?? throw new ArgumentNullException(nameof(clock)); - - _delay = delay; - _duration = duration; - _baseClock = clock; - } - - private void TimerTick(TimeSpan t) - { - - // [<------------- normalizedTotalDur ------------------>] - // [<---- Delay ---->][<---------- Duration ------------>] - // ^- normalizedDelayEnd - // [<---- normalizedInterpVal --->] - - var normalizedInterpVal = 1d; - - if (!MathUtilities.AreClose(_duration.TotalSeconds, 0d)) - { - var normalizedTotalDur = _delay + _duration; - var normalizedDelayEnd = _delay.TotalSeconds / normalizedTotalDur.TotalSeconds; - var normalizedPresentationTime = t.TotalSeconds / normalizedTotalDur.TotalSeconds; - - if (normalizedPresentationTime < normalizedDelayEnd - || MathUtilities.AreClose(normalizedPresentationTime, normalizedDelayEnd)) - { - normalizedInterpVal = 0d; - } - else - { - normalizedInterpVal = (t.TotalSeconds - _delay.TotalSeconds) / _duration.TotalSeconds; - } - } - - // Clamp interpolation value. - if (normalizedInterpVal >= 1d || normalizedInterpVal < 0d) - { - PublishNext(1d); - PublishCompleted(); - } - else - { - PublishNext(normalizedInterpVal); - } - } - - protected override void Unsubscribed() - { - _timerSubscription?.Dispose(); - if (_clock != null) - _clock.PlayState = PlayState.Stop; - } - - protected override void Subscribed() - { - _clock = new Clock(_baseClock); - _timerSubscription = _clock.Subscribe(TimerTick); - PublishNext(0.0d); - } - } -} \ No newline at end of file diff --git a/AvaloniaStyles/Utils/Win32.cs b/AvaloniaStyles/Utils/Win32.cs index 1414d41c3..91589b6e3 100644 --- a/AvaloniaStyles/Utils/Win32.cs +++ b/AvaloniaStyles/Utils/Win32.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Avalonia.Media; +using WDE.Common; namespace AvaloniaStyles.Utils; @@ -56,7 +57,7 @@ public static bool SetDarkMode(IntPtr hwnd, bool on) var msg = Marshal.GetExceptionForHR(result)?.Message; var msg2 = Marshal.GetExceptionForHR(result2)?.Message; - Console.WriteLine($"Can't set window dark mode:\n DWMWA_USE_IMMERSIVE_DARK_MODE method: {msg}\n DWMWA_USE_IMMERSIVE_DARK_MODE_OLD_WINDOWS method: {msg2}"); + LOG.LogWarning($"Can't set window dark mode:\n DWMWA_USE_IMMERSIVE_DARK_MODE method: {msg}\n DWMWA_USE_IMMERSIVE_DARK_MODE_OLD_WINDOWS method: {msg2}"); return false; } @@ -88,7 +89,7 @@ public static bool SetTitleBarColor(IntPtr hwnd, Color color) } var msg = Marshal.GetExceptionForHR(result)?.Message; - Console.WriteLine($"Can't set window caption color: {msg}"); + LOG.LogWarning($"Can't set window caption color: {msg}"); return false; } } \ No newline at end of file diff --git a/BaseDesktopLoader/BaseDesktopLoader.csproj b/BaseDesktopLoader/BaseDesktopLoader.csproj new file mode 100644 index 000000000..56b4b5c80 --- /dev/null +++ b/BaseDesktopLoader/BaseDesktopLoader.csproj @@ -0,0 +1,31 @@ + + + Library + net8.0 + enable + true + + + + ..\bin\$(Configuration)\ + + + + + + + + + + + + + + + + + + + + + diff --git a/BaseDesktopLoader/Program.cs b/BaseDesktopLoader/Program.cs new file mode 100644 index 000000000..57c4aa194 --- /dev/null +++ b/BaseDesktopLoader/Program.cs @@ -0,0 +1,113 @@ +using System.Threading.Tasks; +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using AsyncAwaitBestPractices; +using Avalonia; +using Avalonia.ReactiveUI; +using Avalonia.Threading; +using Projektanker.Icons.Avalonia; +using Projektanker.Icons.Avalonia.MaterialDesign; +using WDE.Common; +using WDE.Common.Tasks; +using WoWDatabaseEditorCore; +using WoWDatabaseEditorCore.Avalonia; +using WoWDatabaseEditorCore.Avalonia.Utils; +using WoWDatabaseEditorCore.Managers; +using WoWDatabaseEditorCore.Services.FileSystemService; + +namespace BaseDesktopLoader +{ + public abstract class BaseProgramLoader + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + public static void Main(System.Type[] modules, string[] args) + { + MigrateMacOsSettings(); + + WoWDatabaseEditorCore.Avalonia.Program.PreloadedModules = modules; + + if (!BeforeBuildApp(args)) + return; + + var app = BuildAvaloniaApp(); + try + { + app.StartWithClassicDesktopLifetime(args); + } + catch (Exception e) + { + FatalErrorHandler.ExceptionOccured(e, args); + } + TheEngine.TheEngine.Deinit(); + } + + private static void MigrateMacOsSettings() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + var localDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var oldLocalDataPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "share"); + + var newSettingsPath = Path.Join(localDataPath, FileSystem.APPLICATION_FOLDER); + var oldSettingsPath = Path.Join(oldLocalDataPath, FileSystem.APPLICATION_FOLDER); + + if (Directory.Exists(oldSettingsPath) && !Directory.Exists(newSettingsPath)) + { + Directory.Move(oldSettingsPath, newSettingsPath); + } + } + } + + public static bool BeforeBuildApp(string[] args) + { + FixCurrentDirectory(); + if (ProgramBootstrap.TryLaunchUpdaterIfNeeded(args)) + return false; + System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; + SafeFireAndForgetExtensions.SetDefaultExceptionHandling(x => LOG.LogError(x)); + TaskScheduler.UnobservedTaskException += (sender, eventArgs) => LOG.LogError(eventArgs.Exception); + GlobalApplication.Arguments.Init(args); + + if (GlobalApplication.Arguments.IsArgumentSet("console")) + { + if (OperatingSystem.IsWindows()) + { + if (!Win32.AttachConsole(Win32.ATTACH_PARENT_PROCESS)) + Win32.AllocConsole(); + } + } + + return true; + } + + private static void FixCurrentDirectory() + { + #pragma warning disable IL3000 + var path = Assembly.GetExecutingAssembly().Location; + #pragma warning restore IL3000 + if (string.IsNullOrEmpty(path)) + path = System.AppContext.BaseDirectory; + var exePath = new FileInfo(path); + if (exePath.Directory != null) + Directory.SetCurrentDirectory(exePath.Directory.FullName); + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + { + IconProvider.Current + .Register(); + + var configuration = AppBuilder.Configure() + .UsePlatformDetect() + .UseReactiveUI() + .LogToTrace(); + + return configuration; + } + } +} diff --git a/DBCD b/DBCD index e79a6456e..f19c8588a 160000 --- a/DBCD +++ b/DBCD @@ -1 +1 @@ -Subproject commit e79a6456e828a4562f05df961a969cc147122097 +Subproject commit f19c8588ae0e021fe917188108b2c9e1f3d2a75d diff --git a/DatabaseTester/ConsoleMessageBoxService.cs b/DatabaseTester/ConsoleMessageBoxService.cs index ae039d0c9..73e591528 100644 --- a/DatabaseTester/ConsoleMessageBoxService.cs +++ b/DatabaseTester/ConsoleMessageBoxService.cs @@ -7,8 +7,5 @@ public class ConsoleMessageBoxService : IMessageBoxService public Task ShowDialog(IMessageBox messageBox) { throw new Exception(messageBox.MainInstruction + messageBox.Content); - Console.WriteLine(messageBox.MainInstruction); - Console.WriteLine(messageBox.Content); - return Task.FromException(new Exception(messageBox.Content)); } } \ No newline at end of file diff --git a/DatabaseTester/DatabaseTester.csproj b/DatabaseTester/DatabaseTester.csproj index c6dd2613b..55a079547 100644 --- a/DatabaseTester/DatabaseTester.csproj +++ b/DatabaseTester/DatabaseTester.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 enable enable @@ -22,7 +22,7 @@ - + diff --git a/DatabaseTester/Program.cs b/DatabaseTester/Program.cs index bae8b9a08..b7d811764 100644 --- a/DatabaseTester/Program.cs +++ b/DatabaseTester/Program.cs @@ -65,7 +65,7 @@ private static bool TryGetDefaultObjectForType(Type type, out object? obj) { obj = null; if (type == typeof(string)) - obj = ""; + obj = "a"; else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && TryGetDefaultObjectForType(type.GetGenericArguments()[0], out var innerNullable)) @@ -299,8 +299,8 @@ public static async Task Test(string[] args, params ICoreVersion[] cores } // methods with > 1 parameters - worldDb.GetScriptFor(0, 0, SmartScriptType.Creature); - worldDb.GetConditionsFor(0, 0, 0); + await worldDb.GetScriptForAsync(0, 0, SmartScriptType.Creature); + await worldDb.GetConditionsForAsync(0, 0, 0); await worldDb.GetConditionsForAsync(IDatabaseProvider.ConditionKeyMask.All, new IDatabaseProvider.ConditionKey(0, 0, 0, 0)); await worldDb.GetConditionsForAsync(IDatabaseProvider.ConditionKeyMask.All, new List(){new IDatabaseProvider.ConditionKey(0, 0, 0, 0)}); await worldDb.FindSmartScriptLinesBy(new (IDatabaseProvider.SmartLinePropertyType what, int whatValue, int parameterIndex, long valueToSearch)[] { (IDatabaseProvider.SmartLinePropertyType.Action, 0, 0, 0) }); diff --git a/Directory.Build.props b/Directory.Build.props index 3dcbf076d..84bcc198d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,10 +2,22 @@ - https://nuget-feed-all.avaloniaui.net/v3/index.json + https://nuget-feed-all.avaloniaui.net/v3/index.json;https://www.myget.org/F/xamlbehaviors-nightly/api/v3/index.json CS0067,CS3021,CS1998,CA1416,CS1591 - 0.10.999-cibuild0044575-beta + $(NoWarn),CS0649 + $(NoWarn),NUnit2005,NUnit2049 + $(NoWarn),CS0436 + + true + CS0414 + $(WarningsNotAsErrors),CS0169 + $(WarningsNotAsErrors),NUnit2005 + $(WarningsNotAsErrors),CS0436 + $(WarningsNotAsErrors),NU5104 + $(WarningsNotAsErrors),CS1574 + + $(WarningsAsErrors),AVP1000, AVP1001, AVP1002, AVP1010, AVP1011, AVP1012, AVP1013, AVP1020, AVP1021, AVP1022, AVP1030, AVP1031, AVP1032, AVP1040, AVA2001 preview @@ -19,4 +31,4 @@ $(OutputPath) $(SolutionDir)bin\doc\$(Configuration)\$(MSBuildProjectName).xml - \ No newline at end of file + diff --git a/Dock b/Dock index 867ffea9f..77017d455 160000 --- a/Dock +++ b/Dock @@ -1 +1 @@ -Subproject commit 867ffea9f5f4ca337f6942e6c9aaf87931de4d32 +Subproject commit 77017d455593d4ae1797cf90a5e298431a414fe4 diff --git a/GeminiGraphEditor/GeminiGraphEditor.csproj b/GeminiGraphEditor/GeminiGraphEditor.csproj index 648893482..5cdb11394 100644 --- a/GeminiGraphEditor/GeminiGraphEditor.csproj +++ b/GeminiGraphEditor/GeminiGraphEditor.csproj @@ -1,6 +1,6 @@  - net7.0-windows7.0 + net8.0-windows7.0 Library false true diff --git a/LoaderAvalonia.Web/AppBundle/Logo.svg b/LoaderAvalonia.Web/AppBundle/Logo.svg new file mode 100644 index 000000000..9685a23af --- /dev/null +++ b/LoaderAvalonia.Web/AppBundle/Logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/LoaderAvalonia.Web/AppBundle/app.css b/LoaderAvalonia.Web/AppBundle/app.css new file mode 100644 index 000000000..a424538ba --- /dev/null +++ b/LoaderAvalonia.Web/AppBundle/app.css @@ -0,0 +1,74 @@ +:root { + --sat: env(safe-area-inset-top); + --sar: env(safe-area-inset-right); + --sab: env(safe-area-inset-bottom); + --sal: env(safe-area-inset-left); +} + +/* HTML styles for the splash screen */ + +.highlight { + color: white; + font-size: 2.5rem; + display: block; +} + +.purple { + color: #8b44ac; +} + +.icon { + opacity: 0.05; + height: 35%; + width: 35%; + position: absolute; + background-repeat: no-repeat; + right: 0px; + bottom: 0px; + margin-right: 3%; + margin-bottom: 5%; + z-index: 5000; + background-position: right bottom; + pointer-events: none; +} + +#avalonia-splash a { + color: whitesmoke; + text-decoration: none; +} + +.center { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} + +#avalonia-splash { + position: relative; + height: 100%; + width: 100%; + color: whitesmoke; + background: #1b2a4e; + font-family: 'Nunito', sans-serif; + background-position: center; + background-size: cover; + background-repeat: no-repeat; + justify-content: center; + align-items: center; +} + +.splash-close { + animation: fadeout 0.25s linear forwards; +} + +@keyframes fadeout { + 0% { + opacity: 100%; + } + + 100% { + opacity: 0; + visibility: collapse; + } +} diff --git a/LoaderAvalonia.Web/AppBundle/favicon.ico b/LoaderAvalonia.Web/AppBundle/favicon.ico new file mode 100644 index 000000000..da8d49ff9 Binary files /dev/null and b/LoaderAvalonia.Web/AppBundle/favicon.ico differ diff --git a/LoaderAvalonia.Web/AppBundle/index.html b/LoaderAvalonia.Web/AppBundle/index.html new file mode 100644 index 000000000..915fecaef --- /dev/null +++ b/LoaderAvalonia.Web/AppBundle/index.html @@ -0,0 +1,30 @@ + + + + + WoW Database Edtor Online Demo Edition + + + + + + + + + + +
+
+
+

+ Powered by + Avalonia UI +

+
+ Avalonia Logo +
+
+ + + + \ No newline at end of file diff --git a/LoaderAvalonia.Web/AppBundle/main.js b/LoaderAvalonia.Web/AppBundle/main.js new file mode 100644 index 000000000..599c341eb --- /dev/null +++ b/LoaderAvalonia.Web/AppBundle/main.js @@ -0,0 +1,31 @@ +import { dotnet } from './_framework/dotnet.js' + +const is_browser = typeof window != "undefined"; +if (!is_browser) throw new Error(`Expected to be running in a browser`); + +const dotnetRuntime = await dotnet + .withDiagnosticTracing(false) + .withApplicationArgumentsFromQuery() + .create(); + +dotnetRuntime.setModuleImports("main.js", { + window: { + history: { + replaceState: (title, href) => globalThis.window.history.replaceState(null, title, href) + } + }, + localStorage: { + getValue: (key) => globalThis.localStorage.getItem(key), + setValue: (key, value) => globalThis.localStorage.setItem(key, value) + } +}); + +const config = dotnetRuntime.getConfig(); + +let href = window.location.href; +if (href.indexOf("?") !== -1) + href = href.slice(0, href.indexOf("?")) +if (href.indexOf("index.html") !== -1) + href = href.slice(0, href.indexOf("index.html")) + +await dotnetRuntime.runMain(config.mainAssemblyName, ["--search", window.location.search, "--href", href]); \ No newline at end of file diff --git a/LoaderAvalonia.Web/LoaderAvalonia.Web.csproj b/LoaderAvalonia.Web/LoaderAvalonia.Web.csproj new file mode 100644 index 000000000..663dd16fc --- /dev/null +++ b/LoaderAvalonia.Web/LoaderAvalonia.Web.csproj @@ -0,0 +1,116 @@ + + + net8.0-browser + browser-wasm + AppBundle\main.js + Exe + enable + nullable + false + 1073741824 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LoaderAvalonia.Web/NullDebuggerService.cs b/LoaderAvalonia.Web/NullDebuggerService.cs new file mode 100644 index 000000000..2a0ff82a2 --- /dev/null +++ b/LoaderAvalonia.Web/NullDebuggerService.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using WDE.Common.Debugging; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullDebuggerService : IDebuggerService +{ + public DebugPointId CreateDebugPoint(IDebugPointSource source, IDebugPointPayload payload) => default; + + public void ScheduleRemoveDebugPoint(DebugPointId id) { } + + public async Task RemoveDebugPointAsync(DebugPointId id, bool remoteAlreadyRemoved = false) { } + + public async Task ClearAllDebugPoints() { } + + public bool TryFindDebugPoint(Func matcher, out DebugPointId id) where T : IDebugPointPayload + { + id = default; + return false; + } + + public async Task RemoveIfAsync(Func matcher, bool remoteAlreadyRemoved = false) where T : IDebugPointPayload { } + + public bool TryGetPayload(DebugPointId id, out T payload) where T : IDebugPointPayload + { + payload = default!; + return false; + } + + public void SetLog(DebugPointId point, string? path) { } + + public void SetEnabled(DebugPointId point, bool enabled) { } + + public void SetActivated(DebugPointId point, bool activated) { } + + public void SetSuspendExecution(DebugPointId point, bool suspend) { } + + public void SetGenerateStacktrace(DebugPointId point, bool generate) { } + + public void SetPayload(DebugPointId id, IDebugPointPayload payload) { } + + public void SetLogCondition(DebugPointId point, string? condition) { } + + public void ForceSetSynchronized(DebugPointId point) { } + + public void ForceSetPending(DebugPointId point) { } + + public string? GetLogFormat(DebugPointId point) => null; + + public string? GetLogCondition(DebugPointId point) => null; + + public bool GetActivated(DebugPointId point) => false; + + public bool GetEnabled(DebugPointId point) => false; + + public bool GetSuspendExecution(DebugPointId point) => false; + + public bool GetGenerateStacktrace(DebugPointId point) => false; + + public bool IsBreakpointHit(DebugPointId point) => false; + + public IDebugPointSource GetSource(DebugPointId point) => null!; + + public bool HasDebugPoint(DebugPointId id) => false; + + public async Task Synchronize(DebugPointId id) { } + + public BreakpointState GetState(DebugPointId breakpoint) => BreakpointState.Pending; + + public bool IsConnected => false; + public IReadOnlyList Sources { get; set; } = Array.Empty(); + public IEnumerable DebugPoints { get; set; } = Array.Empty(); + public event Action? DebugPointAdded; + public event Action? DebugPointRemoving; + public event Action? DebugPointRemoved; + public event Action? DebugPointChanged; +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/NullGameView.cs b/LoaderAvalonia.Web/NullGameView.cs new file mode 100644 index 000000000..bcaef92bd --- /dev/null +++ b/LoaderAvalonia.Web/NullGameView.cs @@ -0,0 +1,16 @@ +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullGameView : IGameViewService +{ + public bool IsSupported => false; + + public void Open() + { + + } +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/NullRemoteConnectorService.cs b/LoaderAvalonia.Web/NullRemoteConnectorService.cs new file mode 100644 index 000000000..2c0ae3ce2 --- /dev/null +++ b/LoaderAvalonia.Web/NullRemoteConnectorService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullRemoteConnectorService : IRemoteConnectorService +{ + public event Action? OnLog; + + public bool IsConnected => false; + + public bool HasValidSettings => true; + + public async Task ExecuteCommand(IRemoteCommand command) + { + return ""; + } + + public async Task ExecuteCommands(IList commands) + { + } + + public event Action? EditorCommandReceived; + public event Action? EditorConnected; + public event Action? EditorDisconnected; + + public IList Merge(IList commands) + { + return commands; + } +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/NullSourceCodePathService.cs b/LoaderAvalonia.Web/NullSourceCodePathService.cs new file mode 100644 index 000000000..9cd322f2a --- /dev/null +++ b/LoaderAvalonia.Web/NullSourceCodePathService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullSourceCodePathService : ISourceCodePathService +{ + public IReadOnlyList SourceCodePaths { get; set; } = Array.Empty(); +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/NullUpdateViewModel.cs b/LoaderAvalonia.Web/NullUpdateViewModel.cs new file mode 100644 index 000000000..c99ff35be --- /dev/null +++ b/LoaderAvalonia.Web/NullUpdateViewModel.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; +using System.Windows.Input; +using WDE.Common.Services; +using WDE.Common.Utils; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullUpdateViewModel : IUpdateViewModel +{ + public event PropertyChangedEventHandler? PropertyChanged; + public bool HasPendingUpdate => false; + public ICommand InstallPendingCommandUpdate { get; } = AlwaysDisabledCommand.Command; +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/NullVisualStudioManagerViewModel.cs b/LoaderAvalonia.Web/NullVisualStudioManagerViewModel.cs new file mode 100644 index 000000000..b5c31a80c --- /dev/null +++ b/LoaderAvalonia.Web/NullVisualStudioManagerViewModel.cs @@ -0,0 +1,11 @@ +using WDE.Common.Managers; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.Web; + +[AutoRegister] +[SingleInstance] +public class NullVisualStudioManagerViewModel : IVisualStudioManagerViewModel +{ + +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/Program.cs b/LoaderAvalonia.Web/Program.cs new file mode 100644 index 000000000..709bf448f --- /dev/null +++ b/LoaderAvalonia.Web/Program.cs @@ -0,0 +1,77 @@ +using System.Runtime.Versioning; +using System.Threading.Tasks; +using Avalonia; +using Avalonia.Browser; +using Avalonia.ReactiveUI; +using WDE.Common.Avalonia; +using WDE.Common.Tasks; +using WDE.CommonViews.Avalonia; +using WDE.Conditions; +using WDE.DatabaseEditors; +using WDE.DatabaseEditors.Avalonia; +using WDE.DbcStore; +using WDE.EventAiEditor.Avalonia; +using WDE.EventScriptsEditor; +using WDE.History; +using WDE.HttpDatabase; +using WDE.LootEditor; +using WDE.MySqlDatabaseCommon; +using WDE.Parameters; +using WDE.Profiles; +using WDE.QueryGenerators; +using WDE.Sessions; +using WDE.SmartScriptEditor.Avalonia; +using WDE.Solutions; +using WDE.Spells; +using WDE.SQLEditor; +using WDE.SqlInterpreter; +using WDE.Trinity; +using WDE.TrinitySmartScriptEditor; +using WoWDatabaseEditorCore.Avalonia; + +[assembly: SupportedOSPlatform("browser")] + +namespace LoaderAvalonia.Web; + +internal partial class Program +{ + static System.Type[] modules = new System.Type[] + { + typeof(CommonAvaloniaModule), + typeof(CommonViewsModule), + typeof(ConditionsModule), + typeof(DatabaseEditorsModule), + typeof(DatabaseEditorsAvaloniaModule), + typeof(MySqlDatabaseCommonModule), + typeof(ParametersModule), + typeof(SmartScriptAvaloniaModule), + typeof(SpellsModule), + typeof(SqlInterpreterModule), + typeof(DbcStoreModule), + typeof(HistoryModule), + typeof(EventAiAvaloniaModule), + typeof(SessionsModule), + typeof(SolutionsModule), + typeof(QueryGeneratorModule), + typeof(TrinityModule), + typeof(SmartScriptModule), + typeof(WebModule), + typeof(LootEditorModule), + typeof(EventScriptsModule), + typeof(HttpDatabaseModule), + typeof(ProfilesModule), + typeof(SqlEditorModule) + }; + + private static async Task Main(string[] args) + { + GlobalApplication.Arguments.Init(args); + await BuildAvaloniaApp() + .WithInterFont() + .UseReactiveUI() + .StartBrowserAppAsync("out"); + } + + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure(); +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/Properties/launchSettings.json b/LoaderAvalonia.Web/Properties/launchSettings.json new file mode 100644 index 000000000..3104f57fd --- /dev/null +++ b/LoaderAvalonia.Web/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "WoWDatabaseEditorDemo": { + "commandName": "Project", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/debug?browser={browserInspectUri}" + } + } +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/WebModule.cs b/LoaderAvalonia.Web/WebModule.cs new file mode 100644 index 000000000..9bcd87976 --- /dev/null +++ b/LoaderAvalonia.Web/WebModule.cs @@ -0,0 +1,8 @@ +using WDE.Module; + +namespace LoaderAvalonia.Web; + +public class WebModule : ModuleBase +{ + +} \ No newline at end of file diff --git a/LoaderAvalonia.Web/runtimeconfig.template.json b/LoaderAvalonia.Web/runtimeconfig.template.json new file mode 100644 index 000000000..c6990ba79 --- /dev/null +++ b/LoaderAvalonia.Web/runtimeconfig.template.json @@ -0,0 +1,11 @@ +{ + "wasmHostProperties": { + "perHostConfig": [ + { + "name": "browser", + "html-path": "index.html", + "Host": "browser" + } + ] + } +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/AppDelegate.cs b/LoaderAvalonia.iOS/AppDelegate.cs new file mode 100644 index 000000000..821de7ab1 --- /dev/null +++ b/LoaderAvalonia.iOS/AppDelegate.cs @@ -0,0 +1,20 @@ +using Avalonia; +using Avalonia.iOS; +using Avalonia.ReactiveUI; +using Foundation; +using WoWDatabaseEditorCore.Avalonia; + +namespace LoaderAvalonia.iOS; + +// The UIApplicationDelegate for the application. This class is responsible for launching the +// User Interface of the application, as well as listening (and optionally responding) to +// application events from iOS. +[Register("AppDelegate")] +public partial class AppDelegate : AvaloniaAppDelegate +{ + protected override AppBuilder CustomizeAppBuilder(AppBuilder builder) + { + return base.CustomizeAppBuilder(builder) + .WithInterFont(); + } +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/Entitlements.plist b/LoaderAvalonia.iOS/Entitlements.plist new file mode 100644 index 000000000..0c67376eb --- /dev/null +++ b/LoaderAvalonia.iOS/Entitlements.plist @@ -0,0 +1,5 @@ + + + + + diff --git a/LoaderAvalonia.iOS/Info.plist b/LoaderAvalonia.iOS/Info.plist new file mode 100644 index 000000000..c28c6c009 --- /dev/null +++ b/LoaderAvalonia.iOS/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDisplayName + MyApp + CFBundleIdentifier + x.mytestapp + CFBundleShortVersionString + 1.0 + CFBundleVersion + 36 + LSRequiresIPhoneOS + + MinimumOSVersion + 13.0 + UIDeviceFamily + + 1 + 2 + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIStatusBarHidden + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/LoaderAvalonia.iOS/LoaderAvalonia.iOS.csproj b/LoaderAvalonia.iOS/LoaderAvalonia.iOS.csproj new file mode 100644 index 000000000..9af42456f --- /dev/null +++ b/LoaderAvalonia.iOS/LoaderAvalonia.iOS.csproj @@ -0,0 +1,51 @@ + + + Exe + net8.0-ios + 13.0 + enable + nullable + false + + + + + Apple Development: b.andy@windowslive.com (Q5L623R3A3) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LoaderAvalonia.iOS/Main.cs b/LoaderAvalonia.iOS/Main.cs new file mode 100644 index 000000000..9405e7dd1 --- /dev/null +++ b/LoaderAvalonia.iOS/Main.cs @@ -0,0 +1,69 @@ +using UIKit; +using WDE.Common.Avalonia; +using WDE.Common.Tasks; +using WDE.CommonViews.Avalonia; +using WDE.Conditions; +using WDE.DatabaseEditors; +using WDE.DatabaseEditors.Avalonia; +using WDE.DbcStore; +using WDE.EventAiEditor.Avalonia; +using WDE.EventScriptsEditor; +using WDE.History; +using WDE.HttpDatabase; +using WDE.LootEditor; +using WDE.MySqlDatabaseCommon; +using WDE.Parameters; +using WDE.Profiles; +using WDE.QueryGenerators; +using WDE.Sessions; +using WDE.SmartScriptEditor.Avalonia; +using WDE.Solutions; +using WDE.Spells; +using WDE.SQLEditor; +using WDE.SqlInterpreter; +using WDE.Trinity; +using WDE.TrinitySmartScriptEditor; + +namespace LoaderAvalonia.iOS; + +public class Application +{ + + static System.Type[] modules = new System.Type[] + { + typeof(iOSModule), + typeof(CommonAvaloniaModule), + typeof(CommonViewsModule), + typeof(ConditionsModule), + typeof(DatabaseEditorsModule), + typeof(DatabaseEditorsAvaloniaModule), + typeof(MySqlDatabaseCommonModule), + typeof(ParametersModule), + typeof(SmartScriptAvaloniaModule), + typeof(SpellsModule), + typeof(SqlInterpreterModule), + typeof(DbcStoreModule), + typeof(HistoryModule), + typeof(EventAiAvaloniaModule), + typeof(SessionsModule), + typeof(SolutionsModule), + typeof(QueryGeneratorModule), + typeof(TrinityModule), + typeof(SmartScriptModule), + typeof(LootEditorModule), + typeof(EventScriptsModule), + typeof(HttpDatabaseModule), + typeof(ProfilesModule), + typeof(SqlEditorModule) + }; + + // This is the main entry point of the application. + static void Main(string[] args) + { + WoWDatabaseEditorCore.Avalonia.Program.PreloadedModules = modules; + GlobalApplication.Arguments.Init(new[]{"--href", "http://192.168.1.106:5000"}); + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullDebuggerService.cs b/LoaderAvalonia.iOS/NullDebuggerService.cs new file mode 100644 index 000000000..f37b6be22 --- /dev/null +++ b/LoaderAvalonia.iOS/NullDebuggerService.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using WDE.Common.Debugging; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullDebuggerService : IDebuggerService +{ + public DebugPointId CreateDebugPoint(IDebugPointSource source, IDebugPointPayload payload) => default; + + public void ScheduleRemoveDebugPoint(DebugPointId id) { } + + public async Task RemoveDebugPointAsync(DebugPointId id, bool remoteAlreadyRemoved = false) { } + + public async Task ClearAllDebugPoints() { } + + public bool TryFindDebugPoint(Func matcher, out DebugPointId id) where T : IDebugPointPayload + { + id = default; + return false; + } + + public async Task RemoveIfAsync(Func matcher, bool remoteAlreadyRemoved = false) where T : IDebugPointPayload { } + + public bool TryGetPayload(DebugPointId id, out T payload) where T : IDebugPointPayload + { + payload = default!; + return false; + } + + public void SetLog(DebugPointId point, string? path) { } + + public void SetEnabled(DebugPointId point, bool enabled) { } + + public void SetActivated(DebugPointId point, bool activated) { } + + public void SetSuspendExecution(DebugPointId point, bool suspend) { } + + public void SetGenerateStacktrace(DebugPointId point, bool generate) { } + + public void SetPayload(DebugPointId id, IDebugPointPayload payload) { } + + public void SetLogCondition(DebugPointId point, string? condition) { } + + public void ForceSetSynchronized(DebugPointId point) { } + + public void ForceSetPending(DebugPointId point) { } + + public string? GetLogFormat(DebugPointId point) => null; + + public string? GetLogCondition(DebugPointId point) => null; + + public bool GetActivated(DebugPointId point) => false; + + public bool GetEnabled(DebugPointId point) => false; + + public bool GetSuspendExecution(DebugPointId point) => false; + + public bool GetGenerateStacktrace(DebugPointId point) => false; + + public bool IsBreakpointHit(DebugPointId point) => false; + + public IDebugPointSource GetSource(DebugPointId point) => null!; + + public bool HasDebugPoint(DebugPointId id) => false; + + public async Task Synchronize(DebugPointId id) { } + + public BreakpointState GetState(DebugPointId breakpoint) => BreakpointState.Pending; + + public bool IsConnected => false; + public IReadOnlyList Sources { get; set; } = Array.Empty(); + public IEnumerable DebugPoints { get; set; } = Array.Empty(); + public event Action? DebugPointAdded; + public event Action? DebugPointRemoving; + public event Action? DebugPointRemoved; + public event Action? DebugPointChanged; +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullGameView.cs b/LoaderAvalonia.iOS/NullGameView.cs new file mode 100644 index 000000000..646f3143f --- /dev/null +++ b/LoaderAvalonia.iOS/NullGameView.cs @@ -0,0 +1,16 @@ +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullGameView : IGameViewService +{ + public bool IsSupported => false; + + public void Open() + { + + } +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullRemoteConnectorService.cs b/LoaderAvalonia.iOS/NullRemoteConnectorService.cs new file mode 100644 index 000000000..fce263e45 --- /dev/null +++ b/LoaderAvalonia.iOS/NullRemoteConnectorService.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullRemoteConnectorService : IRemoteConnectorService +{ + public event Action? OnLog; + + public bool IsConnected => false; + + public bool HasValidSettings => true; + + public async Task ExecuteCommand(IRemoteCommand command) + { + return ""; + } + + public async Task ExecuteCommands(IList commands) + { + } + + public event Action? EditorCommandReceived; + public event Action? EditorConnected; + public event Action? EditorDisconnected; + + public IList Merge(IList commands) + { + return commands; + } +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullSourceCodePathService.cs b/LoaderAvalonia.iOS/NullSourceCodePathService.cs new file mode 100644 index 000000000..e53d2f464 --- /dev/null +++ b/LoaderAvalonia.iOS/NullSourceCodePathService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using WDE.Common.Services; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullSourceCodePathService : ISourceCodePathService +{ + public IReadOnlyList SourceCodePaths { get; set; } = Array.Empty(); +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullUpdateViewModel.cs b/LoaderAvalonia.iOS/NullUpdateViewModel.cs new file mode 100644 index 000000000..03ff6d1e7 --- /dev/null +++ b/LoaderAvalonia.iOS/NullUpdateViewModel.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; +using System.Windows.Input; +using WDE.Common.Services; +using WDE.Common.Utils; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullUpdateViewModel : IUpdateViewModel +{ + public event PropertyChangedEventHandler? PropertyChanged; + public bool HasPendingUpdate => false; + public ICommand InstallPendingCommandUpdate { get; } = AlwaysDisabledCommand.Command; +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/NullVisualStudioManagerViewModel.cs b/LoaderAvalonia.iOS/NullVisualStudioManagerViewModel.cs new file mode 100644 index 000000000..aaf49c484 --- /dev/null +++ b/LoaderAvalonia.iOS/NullVisualStudioManagerViewModel.cs @@ -0,0 +1,11 @@ +using WDE.Common.Managers; +using WDE.Module.Attributes; + +namespace LoaderAvalonia.iOS; + +[AutoRegister] +[SingleInstance] +public class NullVisualStudioManagerViewModel : IVisualStudioManagerViewModel +{ + +} \ No newline at end of file diff --git a/LoaderAvalonia.iOS/Resources/LaunchScreen.xib b/LoaderAvalonia.iOS/Resources/LaunchScreen.xib new file mode 100644 index 000000000..4e33f2f48 --- /dev/null +++ b/LoaderAvalonia.iOS/Resources/LaunchScreen.xib @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LoaderAvalonia.iOS/iOSModule.cs b/LoaderAvalonia.iOS/iOSModule.cs new file mode 100644 index 000000000..0db37a824 --- /dev/null +++ b/LoaderAvalonia.iOS/iOSModule.cs @@ -0,0 +1,8 @@ +using WDE.Module; + +namespace LoaderAvalonia.iOS; + +public class iOSModule : ModuleBase +{ + +} \ No newline at end of file diff --git a/LoaderAvalonia/LoaderAvalonia.csproj b/LoaderAvalonia/LoaderAvalonia.csproj index 57612d293..605a23c1b 100644 --- a/LoaderAvalonia/LoaderAvalonia.csproj +++ b/LoaderAvalonia/LoaderAvalonia.csproj @@ -2,24 +2,30 @@ WinExe - net7.0 + net8.0 Debug;Release AnyCPU ../WoWDatabaseEditorCore.Avalonia/Icon.ico - WoWDatabaseEditorCore.Avalonia + WoWDatabaseEditor false ..\bin\$(Configuration)\ - + + + + + + app.manifest + diff --git a/LoaderAvalonia/Program.cs b/LoaderAvalonia/Program.cs index 11f064679..ba641b8db 100644 --- a/LoaderAvalonia/Program.cs +++ b/LoaderAvalonia/Program.cs @@ -1,3 +1,8 @@ +using Avalonia; +using Avalonia.ReactiveUI; +using BaseDesktopLoader; +using Projektanker.Icons.Avalonia; +using Projektanker.Icons.Avalonia.MaterialDesign; using WDE.AzerothCore; using WDE.CMaNGOS; using WDE.CMMySqlDatabase; @@ -39,10 +44,10 @@ using WDE.PathPreviewTool; using WDE.FirstTimeWizard; using WDE.LootEditor; -using WDE.LootEditor.Models; using WDE.QueryGenerators; using WDE.Profiles; using WDE.SqlWorkbench; +using WoWDatabaseEditorCore.Avalonia; namespace LoaderAvalonia { @@ -97,8 +102,18 @@ public static void Main(string[] args) typeof(SqlWorkbenchModule), typeof(DebuggerModule) }; - WoWDatabaseEditorCore.Avalonia.Program.PreloadedModules = modules; - WoWDatabaseEditorCore.Avalonia.Program.Main(args); + BaseProgramLoader.Main(modules, args); + } + + // Avalonia configuration, don't remove; only used by visual designer. + public static AppBuilder BuildAvaloniaApp() + { + var configuration = AppBuilder.Configure() + .UsePlatformDetect() + .UseReactiveUI() + .LogToTrace(); + + return configuration; } } } \ No newline at end of file diff --git a/Modules/AvaloniaGraph/AvaloniaGraph.csproj b/Modules/AvaloniaGraph/AvaloniaGraph.csproj index 9ac8d398d..d0ec9b0f6 100644 --- a/Modules/AvaloniaGraph/AvaloniaGraph.csproj +++ b/Modules/AvaloniaGraph/AvaloniaGraph.csproj @@ -1,10 +1,10 @@ - net7.0 + net8.0 Debug;Release AnyCPU enable - nullable + $(WarningsAsErrors),nullable diff --git a/Modules/AvaloniaGraph/Controls/BezierLine.cs b/Modules/AvaloniaGraph/Controls/BezierLine.cs index db392ec27..448c224cc 100644 --- a/Modules/AvaloniaGraph/Controls/BezierLine.cs +++ b/Modules/AvaloniaGraph/Controls/BezierLine.cs @@ -11,7 +11,7 @@ public class BezierLine : Shape //, ICustomHitTest AvaloniaProperty.Register(nameof(StartPoint)); public static readonly StyledProperty EndPointProperty = - AvaloniaProperty.Register(nameof(StartPoint)); + AvaloniaProperty.Register(nameof(EndPoint)); static BezierLine() { @@ -74,20 +74,18 @@ protected virtual PathSegments GetSegments() protected override Geometry? CreateDefiningGeometry() { + var figure = new PathFigure + { + IsFilled = false, + StartPoint = Relative + ? StartPoint - new Point(Math.Min(StartPoint.X, EndPoint.X), Math.Min(StartPoint.Y, EndPoint.Y)) + : StartPoint, + Segments = GetSegments(), + IsClosed = false + }; return new PathGeometry { - Figures = - { - new PathFigure - { - IsFilled = false, - StartPoint = Relative - ? StartPoint - new Point(Math.Min(StartPoint.X, EndPoint.X), Math.Min(StartPoint.Y, EndPoint.Y)) - : StartPoint, - Segments = GetSegments(), - IsClosed = false - } - } + Figures = new PathFigures(){figure} }; } diff --git a/Modules/AvaloniaGraph/Controls/ConnectionItem.cs b/Modules/AvaloniaGraph/Controls/ConnectionItem.cs index a1d083528..49d9af9e8 100644 --- a/Modules/AvaloniaGraph/Controls/ConnectionItem.cs +++ b/Modules/AvaloniaGraph/Controls/ConnectionItem.cs @@ -9,7 +9,7 @@ namespace AvaloniaGraph.Controls; public class ConnectionItem : ListBoxItem { public static readonly StyledProperty TopLeftPositionProperty = - AvaloniaProperty.Register(nameof(TopLeftPosition), + AvaloniaProperty.Register(nameof(TopLeftPosition), defaultBindingMode: BindingMode.TwoWay); private GraphControl? ParentGraphControl => this.FindAncestorOfType(); diff --git a/Modules/AvaloniaGraph/Controls/ConnectionsContainer.cs b/Modules/AvaloniaGraph/Controls/ConnectionsContainer.cs index 9c01643a3..dbe64bc48 100644 --- a/Modules/AvaloniaGraph/Controls/ConnectionsContainer.cs +++ b/Modules/AvaloniaGraph/Controls/ConnectionsContainer.cs @@ -5,15 +5,17 @@ namespace AvaloniaGraph.Controls; -public class ConnectionsContainer : ListBox, IStyleable +public class ConnectionsContainer : ListBox { - Type IStyleable.StyleKey => typeof(ListBox); + protected override Type StyleKeyOverride => typeof(ListBox); - protected override IItemContainerGenerator CreateItemContainerGenerator() + protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) { - return new ItemContainerGenerator( - this, - ContentControl.ContentProperty, - ContentControl.ContentTemplateProperty); + return new ConnectionItem(); + } + + protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) + { + return this.NeedsContainer(item, out recycleKey); } } \ No newline at end of file diff --git a/Modules/AvaloniaGraph/Controls/ConnectorItem.cs b/Modules/AvaloniaGraph/Controls/ConnectorItem.cs index aeb564daf..8a2b920cb 100644 --- a/Modules/AvaloniaGraph/Controls/ConnectorItem.cs +++ b/Modules/AvaloniaGraph/Controls/ConnectorItem.cs @@ -79,7 +79,10 @@ private void UpdatePosition() centerPoint = new Point(0, Bounds.Height / 2); else if (attachMode == ConnectorAttachMode.Right) centerPoint = new Point(Bounds.Width, Bounds.Height / 2); - Position = this.TranslatePoint(centerPoint, ParentCanvas) ?? centerPoint; + if (ParentCanvas == null) + SetCurrentValue(PositionProperty, centerPoint); + else + SetCurrentValue(PositionProperty, this.TranslatePoint(centerPoint, ParentCanvas) ?? centerPoint); } #region Dependency properties diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectionDragCompletedEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectionDragCompletedEventArgs.cs index 0eabcfa15..5df330aef 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectionDragCompletedEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectionDragCompletedEventArgs.cs @@ -6,7 +6,7 @@ namespace AvaloniaGraph.Controls; public class ConnectionDragCompletedEventArgs : ConnectionDragEventArgs { public ConnectionDragCompletedEventArgs(RoutedEvent routedEvent, - IInteractive? source, + Interactive? source, GraphNodeItemView? elementItem, object connection, ConnectorItem sourceConnectorItem, diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectionDragEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectionDragEventArgs.cs index 647c7393d..6baab7689 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectionDragEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectionDragEventArgs.cs @@ -4,24 +4,25 @@ namespace AvaloniaGraph.Controls; -public abstract class ConnectionDragEventArgs : PointerEventArgs +public abstract class ConnectionDragEventArgs : RoutedEventArgs { protected ConnectionDragEventArgs(RoutedEvent routedEvent, - IInteractive? source, + Interactive? source, GraphNodeItemView? elementItem, ConnectorItem sourceConnectorItem, - PointerEventArgs baseArgs) : base(routedEvent, source, - baseArgs.Pointer, - (baseArgs.Source as IVisual)?.VisualRoot, - baseArgs.GetPosition(null), - baseArgs.Timestamp, - baseArgs.GetCurrentPoint(null).Properties, - baseArgs.KeyModifiers) + PointerEventArgs baseArgs) : base(routedEvent, source) { ElementItem = elementItem; SourceConnector = sourceConnectorItem; + BaseArgs = baseArgs; } + public PointerEventArgs BaseArgs { get; } public GraphNodeItemView? ElementItem { get; } public ConnectorItem SourceConnector { get; } + + + public IPointer Pointer => BaseArgs.Pointer; + public ulong Timestamp => BaseArgs.Timestamp; + public KeyModifiers KeyModifiers => BaseArgs.KeyModifiers; } \ No newline at end of file diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectionDraggingEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectionDraggingEventArgs.cs index c2d944bf7..70d304dcc 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectionDraggingEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectionDraggingEventArgs.cs @@ -6,7 +6,7 @@ namespace AvaloniaGraph.Controls; public class ConnectionDraggingEventArgs : ConnectionDragEventArgs { public ConnectionDraggingEventArgs(RoutedEvent routedEvent, - IInteractive? source, + Interactive? source, GraphNodeItemView? elementItem, object connection, ConnectorItem connectorItem, diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemBaseEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemBaseEventArgs.cs index 82e97f90d..967c41efa 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemBaseEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemBaseEventArgs.cs @@ -4,21 +4,19 @@ namespace AvaloniaGraph.Controls; -public abstract class ConnectorItemBaseEventArgs : PointerEventArgs +public abstract class ConnectorItemBaseEventArgs : RoutedEventArgs { public ConnectorItemBaseEventArgs(RoutedEvent routedEvent, - IInteractive? source, + Interactive? source, PointerEventArgs baseArgs) : - base(routedEvent, source, - baseArgs.Pointer, - (baseArgs.Source as IVisual)?.VisualRoot, - baseArgs.GetPosition(null), - baseArgs.Timestamp, - baseArgs.GetCurrentPoint(null).Properties, - baseArgs.KeyModifiers) + base(routedEvent, source) { BaseArgs = baseArgs; } public PointerEventArgs BaseArgs { get; } + + public IPointer Pointer => BaseArgs.Pointer; + public ulong Timestamp => BaseArgs.Timestamp; + public KeyModifiers KeyModifiers => BaseArgs.KeyModifiers; } \ No newline at end of file diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDragCompletedEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDragCompletedEventArgs.cs index f3dda32d4..45d185473 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDragCompletedEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDragCompletedEventArgs.cs @@ -6,7 +6,7 @@ namespace AvaloniaGraph.Controls; public class ConnectorItemDragCompletedEventArgs : ConnectorItemBaseEventArgs { public ConnectorItemDragCompletedEventArgs(RoutedEvent routedEvent, - IInteractive? source, PointerEventArgs baseArgs) : base(routedEvent, source, baseArgs) + Interactive? source, PointerEventArgs baseArgs) : base(routedEvent, source, baseArgs) { } } diff --git a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDraggingEventArgs.cs b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDraggingEventArgs.cs index 6add1d4da..41b66aff6 100644 --- a/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDraggingEventArgs.cs +++ b/Modules/AvaloniaGraph/Controls/Events/ConnectorItemDraggingEventArgs.cs @@ -6,7 +6,7 @@ namespace AvaloniaGraph.Controls; public class ConnectorItemDraggingEventArgs : ConnectorItemBaseEventArgs { public ConnectorItemDraggingEventArgs(RoutedEvent routedEvent, - IInteractive? source, + Interactive? source, double horizontalChange, double verticalChange, PointerEventArgs baseArgs) : diff --git a/Modules/AvaloniaGraph/Controls/GraphControl.cs b/Modules/AvaloniaGraph/Controls/GraphControl.cs index 80634417f..25a0f7239 100644 --- a/Modules/AvaloniaGraph/Controls/GraphControl.cs +++ b/Modules/AvaloniaGraph/Controls/GraphControl.cs @@ -29,16 +29,16 @@ public GraphControl() public IList SelectedElements => nodesContainer?.SelectedItems ?? new List(); - public IEnumerable ElementsView => nodesContainer?.Items ?? Enumerable.Empty(); + public IEnumerable ElementsView => nodesContainer?.ItemsSource ?? Array.Empty(); public event EventHandler? SelectionChanged; protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { - nodesContainer = (NodesContainer)e.NameScope.Find("PART_ElementItemsControl"); + nodesContainer = e.NameScope.Get("PART_ElementItemsControl"); nodesContainer.SelectionChanged += OnNodesContainerSelectChanged; - connectionsContainer = (ConnectionsContainer)e.NameScope.Find("PART_ConnectionItemsControl"); + connectionsContainer = e.NameScope.Get("PART_ConnectionItemsControl"); connectionsContainer.SelectionChanged += OnConnectionsContainerSelectChanged; base.OnApplyTemplate(e); @@ -55,20 +55,20 @@ private void OnNodesContainerSelectChanged(object? sender, SelectionChangedEvent //if (e.AddedItems.Count > 0) // connectionItemsControl.SelectedItem = null; if (SelectionChanged != null) - SelectionChanged(this, new SelectionChangedEventArgs(e.RoutedEvent, e.RemovedItems, e.AddedItems)); + SelectionChanged(this, new SelectionChangedEventArgs(e.RoutedEvent!, e.RemovedItems, e.AddedItems)); } protected override void OnPointerPressed(PointerPressedEventArgs e) { - nodesContainer!.SelectedItems.Clear(); - connectionsContainer!.SelectedItems.Clear(); + nodesContainer!.SelectedItems!.Clear(); + connectionsContainer!.SelectedItems!.Clear(); base.OnPointerPressed(e); } public int GetMaxZIndex() { - return nodesContainer!.ItemContainerGenerator.Containers - .Select(elementItem => ((GraphNodeItemView)elementItem.ContainerControl).ZIndex) + return nodesContainer!.ItemsView.Select(x => nodesContainer.ContainerFromItem(x!)) + .Select(elementItem => ((GraphNodeItemView)elementItem!.Parent!).ZIndex) .Concat(new[] { 0 }) .Max(); } @@ -115,9 +115,9 @@ public IList SelectedConnections AvaloniaProperty.Register( nameof(ConnectionItemTemplate)); - public DataTemplate ConnectionItemTemplate + public IDataTemplate ConnectionItemTemplate { - get => (DataTemplate)GetValue(ConnectionItemTemplateProperty); + get => (IDataTemplate)GetValue(ConnectionItemTemplateProperty); set => SetValue(ConnectionItemTemplateProperty, value); } diff --git a/Modules/AvaloniaGraph/Controls/GraphNodeItemView.cs b/Modules/AvaloniaGraph/Controls/GraphNodeItemView.cs index 50e7f8fc6..aff23ebf6 100644 --- a/Modules/AvaloniaGraph/Controls/GraphNodeItemView.cs +++ b/Modules/AvaloniaGraph/Controls/GraphNodeItemView.cs @@ -20,7 +20,7 @@ public void BringToFront() return; var maxZ = ParentGraphControl.GetMaxZIndex(); - ZIndex = maxZ + 1; + SetCurrentValue(ZIndexProperty, maxZ + 1); } #region Dependency properties @@ -52,16 +52,16 @@ public bool IsDragging get => GetValue(IsDraggingProperty); set => SetValue(IsDraggingProperty, value); } - - public static readonly StyledProperty ZIndexProperty = AvaloniaProperty.Register( - nameof(ZIndex), - defaultBindingMode: BindingMode.TwoWay); - - public int ZIndex - { - get => GetValue(ZIndexProperty); - set => SetValue(ZIndexProperty, value); - } + // + // public static readonly StyledProperty ZIndexProperty = AvaloniaProperty.Register( + // nameof(ZIndex), + // defaultBindingMode: BindingMode.TwoWay); + // + // public int ZIndex + // { + // get => GetValue(ZIndexProperty); + // set => SetValue(ZIndexProperty, value); + // } #endregion @@ -76,7 +76,7 @@ private void DoSelection() return; ParentGraphControl.ClearSelection(); - IsSelected = true; + SetCurrentValue(IsSelectedProperty, true); } protected override void OnPointerPressed(PointerPressedEventArgs e) @@ -124,7 +124,7 @@ protected override void OnPointerMoved(PointerEventArgs e) { startX = X; startY = Y; - IsDragging = true; + SetCurrentValue(IsDraggingProperty, true); //CaptureMouse(); } @@ -140,7 +140,7 @@ protected override void OnPointerReleased(PointerReleasedEventArgs e) if (IsDragging) //ReleaseMouseCapture(); - IsDragging = false; + SetCurrentValue(IsDraggingProperty, false); } e.Handled = true; diff --git a/Modules/AvaloniaGraph/Controls/NodesContainer.cs b/Modules/AvaloniaGraph/Controls/NodesContainer.cs index 38b0dd060..adeb57c2c 100644 --- a/Modules/AvaloniaGraph/Controls/NodesContainer.cs +++ b/Modules/AvaloniaGraph/Controls/NodesContainer.cs @@ -5,15 +5,17 @@ namespace AvaloniaGraph.Controls; -public class NodesContainer : ListBox, IStyleable +public class NodesContainer : ListBox { - Type IStyleable.StyleKey => typeof(ListBox); + protected override Type StyleKeyOverride => typeof(ListBox); + + protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) + { + return new GraphNodeItemView(); + } - protected override IItemContainerGenerator CreateItemContainerGenerator() + protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) { - return new ItemContainerGenerator( - this, - ContentControl.ContentProperty, - ContentControl.ContentTemplateProperty); + return this.NeedsContainer(item, out recycleKey); } } \ No newline at end of file diff --git a/Modules/AvaloniaGraph/Style.axaml b/Modules/AvaloniaGraph/Style.axaml index b33eb66c2..a575f3e4c 100644 --- a/Modules/AvaloniaGraph/Style.axaml +++ b/Modules/AvaloniaGraph/Style.axaml @@ -94,8 +94,8 @@ @@ -106,12 +106,11 @@ @@ -119,9 +118,9 @@ @@ -132,12 +131,11 @@ diff --git a/Modules/CrashReport/App.axaml b/Modules/CrashReport/App.axaml index a93aefb40..277fcb43a 100644 --- a/Modules/CrashReport/App.axaml +++ b/Modules/CrashReport/App.axaml @@ -2,15 +2,14 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:crashReport="clr-namespace:CrashReport" x:Class="CrashReport.App" + RequestedThemeVariant="Default" > - - - + \ No newline at end of file diff --git a/Modules/CrashReport/AvaloniaViewLocator.cs b/Modules/CrashReport/AvaloniaViewLocator.cs index 500d736d0..5133d6e03 100644 --- a/Modules/CrashReport/AvaloniaViewLocator.cs +++ b/Modules/CrashReport/AvaloniaViewLocator.cs @@ -1,12 +1,13 @@ using System; using Avalonia.Controls; using Avalonia.Controls.Templates; +using Avalonia.Markup.Xaml.Templates; namespace CrashReport; public class AvaloniaViewLocator : IDataTemplate { - public IControl Build(object? param) + public Control? Build(object? param) { if (param == null) return new TextBlock(){Text = "Null model"}; @@ -25,6 +26,6 @@ public IControl Build(object? param) public bool Match(object? data) { - return data is not IControl && data != null && data is not string; + return data is not Control && data != null && data is not string; } } \ No newline at end of file diff --git a/Modules/CrashReport/CrashReport.csproj b/Modules/CrashReport/CrashReport.csproj index b44d42286..76419674b 100644 --- a/Modules/CrashReport/CrashReport.csproj +++ b/Modules/CrashReport/CrashReport.csproj @@ -1,9 +1,9 @@  WinExe - net7.0 + net8.0 enable - nullable + $(WarningsAsErrors),nullable Icon.ico true app.manifest @@ -17,6 +17,7 @@ + diff --git a/Modules/CrashReport/CrashReportView.axaml b/Modules/CrashReport/CrashReportView.axaml index 1c2bfd8e5..9b6f13954 100644 --- a/Modules/CrashReport/CrashReportView.axaml +++ b/Modules/CrashReport/CrashReportView.axaml @@ -15,15 +15,16 @@ - The editor has crashed 😭 + The editor has crashed 😭 - I am very sorry, but due to some internal problem, the editor has crashed. This report will help me prevent it in the future, so if it happens again, please report the error on github. + I am very sorry, but due to some internal problem, the editor has crashed. This report will help me prevent it in the future, so consider sending the report to the authors. Crash report: + - + diff --git a/Modules/CrashReport/CrashReportViewModel.cs b/Modules/CrashReport/CrashReportViewModel.cs index e96683d1b..9da5b477e 100644 --- a/Modules/CrashReport/CrashReportViewModel.cs +++ b/Modules/CrashReport/CrashReportViewModel.cs @@ -1,10 +1,24 @@ using System; +using System.Collections.Generic; +using System.ComponentModel; using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Runtime.CompilerServices; +using System.Windows.Input; +using AsyncAwaitBestPractices.MVVM; +using Newtonsoft.Json; +using WDE.Common.Factories; +using WDE.Common.Services; +using WDE.Common.Utils; namespace CrashReport; -public class CrashReportViewModel +public class CrashReportViewModel : INotifyPropertyChanged { + private readonly IApplicationReleaseConfiguration configuration; + private readonly IHttpClientFactory clientFactory; public string CrashReport { get; } private static string APPLICATION_FOLDER = "WoWDatabaseEditor"; @@ -14,12 +28,63 @@ public class CrashReportViewModel private static string WDE_DATA_FOLDER => Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), APPLICATION_FOLDER); private static string FATAL_LOG_FILE => Path.Join(WDE_DATA_FOLDER, LOG_FILE); private static string FATAL_LOG_FILE_OLD => Path.Join(WDE_DATA_FOLDER, LOG_FILE_OLD); - - public CrashReportViewModel() + + private bool reportSent; + public AsyncCommand UploadReportCommand { get; } + + public string SendCrashLogButtonText { get; private set; } = "Send the crash log"; + + public CrashReportViewModel(IApplicationReleaseConfiguration configuration, IHttpClientFactory clientFactory) { + this.configuration = configuration; + this.clientFactory = clientFactory; if (File.Exists(FATAL_LOG_FILE)) CrashReport = File.ReadAllText(FATAL_LOG_FILE); else + { CrashReport = "(crash log not found :/)"; + reportSent = true; + } + + var server = configuration.GetString("UPDATE_SERVER"); + if (string.IsNullOrEmpty(server)) + reportSent = true; + + UploadReportCommand = new AsyncCommand(async () => + { + reportSent = true; + UploadReportCommand?.RaiseCanExecuteChanged(); + + var httpClient = clientFactory.Factory(); + try + { + await httpClient.PostAsync(Path.Join(server, "Log", "Send"), new StringContent(JsonConvert.SerializeObject(new + { + log = CrashReport + }), new MediaTypeHeaderValue("application/json"))); + SendCrashLogButtonText = "Crash log sent!"; + OnPropertyChanged(nameof(SendCrashLogButtonText)); + } + catch (Exception e) + { + SendCrashLogButtonText = "Couldn't sent the crashlog: " + e.Message; + OnPropertyChanged(nameof(SendCrashLogButtonText)); + } + }, _ => !reportSent); + } + + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) + { + if (EqualityComparer.Default.Equals(field, value)) return false; + field = value; + OnPropertyChanged(propertyName); + return true; } } \ No newline at end of file diff --git a/Modules/CrashReport/MainWindowViewModel.cs b/Modules/CrashReport/MainWindowViewModel.cs index 9ab18e7f9..4418e1118 100644 --- a/Modules/CrashReport/MainWindowViewModel.cs +++ b/Modules/CrashReport/MainWindowViewModel.cs @@ -30,15 +30,6 @@ public class MainWindowViewModel : ITaskProgress, INotifyPropertyChanged public MainWindowViewModel() { - if (GlobalApplication.Arguments.IsArgumentSet("crashed")) - { - MainContent = new CrashReportViewModel(); - } - else - { - MainContent = new NoCrashViewModel(); - } - RestartEditorWithConsoleCommand = new DelegateCommand(() => { var locator = new ProgramFinder(); @@ -75,8 +66,9 @@ public MainWindowViewModel() IFileSystem fs = new FileSystem(); var releaseConfig = new ApplicationReleaseConfiguration(fs); var applicationVersion = new ApplicationVersion(releaseConfig); + var httpFactory = new HttpClientFactory(applicationVersion); var updateService = new UpdateService(new UpdateServerDataProvider(releaseConfig), - new UpdateClientFactory(new HttpClientFactory(applicationVersion)), + new UpdateClientFactory(httpFactory), new ApplicationVersion(releaseConfig), new ApplicationImpl(), fs, @@ -91,6 +83,16 @@ public MainWindowViewModel() await updateService.DownloadLatestVersion(this); await updateService.CloseForUpdate(); }, () => updateService.CanCheckForUpdates()); + + + if (GlobalApplication.Arguments.IsArgumentSet("crashed")) + { + MainContent = new CrashReportViewModel(releaseConfig, httpFactory); + } + else + { + MainContent = new NoCrashViewModel(); + } } public TaskState State { get; set; } diff --git a/Modules/CrashReport/NoCrashView.axaml b/Modules/CrashReport/NoCrashView.axaml index 25e516f26..55abc81f0 100644 --- a/Modules/CrashReport/NoCrashView.axaml +++ b/Modules/CrashReport/NoCrashView.axaml @@ -15,10 +15,10 @@ - The editor has not crashed 🙂 + The editor has not crashed 🙂 - It looks like the editor hasn't crashed, it is just you who manually started this CrashReport app. You can use it to redownload the latest version. + It looks like the editor hasn't crashed, you just manually started this CrashReport app. You can use it to redownload the latest version. diff --git a/Modules/CrashReport/Program.cs b/Modules/CrashReport/Program.cs index dc383dee0..2e4f499f5 100644 --- a/Modules/CrashReport/Program.cs +++ b/Modules/CrashReport/Program.cs @@ -22,7 +22,9 @@ public static void Main(string[] args) private static void FixCurrentDirectory() { + #pragma warning disable IL3000 var path = Assembly.GetExecutingAssembly().Location; + #pragma warning restore IL3000 if (string.IsNullOrEmpty(path)) path = System.AppContext.BaseDirectory; var exePath = new FileInfo(path); @@ -34,6 +36,6 @@ private static void FixCurrentDirectory() public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() - //.WithInterFont() // ava11 + .WithInterFont() .LogToTrace(); } \ No newline at end of file diff --git a/Modules/WDE.AnniversaryInfo/Services/CommentPublisherService.cs b/Modules/WDE.AnniversaryInfo/Services/CommentPublisherService.cs index bfcc1f791..6429da42d 100644 --- a/Modules/WDE.AnniversaryInfo/Services/CommentPublisherService.cs +++ b/Modules/WDE.AnniversaryInfo/Services/CommentPublisherService.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Avalonia.Input; using Newtonsoft.Json; +using WDE.Common; using WDE.Common.Factories; using WDE.Common.Services; using WDE.Module.Attributes; @@ -47,7 +48,7 @@ public async Task Publish(string username, string text) } catch (Exception e) { - Console.WriteLine(e); + LOG.LogError(e); return CommentResult.InternetProblem; } } diff --git a/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml b/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml index f1f408dbb..74209285e 100644 --- a/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml +++ b/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml @@ -42,7 +42,7 @@ - + @@ -55,7 +55,7 @@ - + diff --git a/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml.cs b/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml.cs index f891e532f..ff01f5994 100644 --- a/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml.cs +++ b/Modules/WDE.AnniversaryInfo/Views/TimelineView.axaml.cs @@ -4,7 +4,7 @@ namespace WDE.AnniversaryInfo.Views; -public class TimelineView : UserControl +public partial class TimelineView : UserControl { public TimelineView() { diff --git a/Modules/WDE.AnniversaryInfo/WDE.AnniversaryInfo.csproj b/Modules/WDE.AnniversaryInfo/WDE.AnniversaryInfo.csproj index 553453bb0..131a34dc2 100644 --- a/Modules/WDE.AnniversaryInfo/WDE.AnniversaryInfo.csproj +++ b/Modules/WDE.AnniversaryInfo/WDE.AnniversaryInfo.csproj @@ -1,12 +1,12 @@ - net7.0 + net8.0 0.0.0.0 0.0.0.0 Debug;Release AnyCPU enable - nullable + $(WarningsAsErrors),nullable diff --git a/Modules/WDE.DatabaseDefinitionEditor/DatabaseDefinitionEditorModule.cs b/Modules/WDE.DatabaseDefinitionEditor/DatabaseDefinitionEditorModule.cs index b08b56a9d..9a1379bc0 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/DatabaseDefinitionEditorModule.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/DatabaseDefinitionEditorModule.cs @@ -1,4 +1,7 @@ -using WDE.Common.Windows; +using System; +using Avalonia; +using Avalonia.Markup.Xaml.Styling; +using WDE.Common.Windows; using WDE.DatabaseDefinitionEditor.ViewModels; using WDE.DatabaseDefinitionEditor.Views; using WDE.Module; @@ -14,5 +17,7 @@ public override void RegisterViews(IViewLocator viewLocator) viewLocator.Bind(); // table editor //viewLocator.Bind(); + + Application.Current!.Styles.Add(new StyleInclude(new Uri("resm:Styles?assembly=WDE.DatabaseDefinitionEditor")){Source = new Uri("avares://WDE.DatabaseDefinitionEditor/Themes/Generic.axaml")}); } } \ No newline at end of file diff --git a/Modules/WDE.DatabaseDefinitionEditor/ViewModels/DefinitionEditorViewModel.cs b/Modules/WDE.DatabaseDefinitionEditor/ViewModels/DefinitionEditorViewModel.cs index c71ec51c6..51ccfeaad 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/ViewModels/DefinitionEditorViewModel.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/ViewModels/DefinitionEditorViewModel.cs @@ -11,6 +11,7 @@ using Avalonia.Input; using Avalonia.Threading; using DynamicData.Binding; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using PropertyChanged.SourceGenerator; using WDE.Common.CoreVersion; @@ -420,7 +421,9 @@ private async Task RefreshPreview(DatabaseTableDefinitionJson? json, Defin var tf = tg.Fields[j]; var of = og.Fields[j]; if (tf != of) - {Console.WriteLine("At index " + i + "/" + j + " there is a diff");} + { + LOG.LogWarning("At index " + i + "/" + j + " there is a diff"); + } } } } diff --git a/Modules/WDE.DatabaseDefinitionEditor/ViewModels/SourceTreeTableDefinitionEditorProvider.cs b/Modules/WDE.DatabaseDefinitionEditor/ViewModels/SourceTreeTableDefinitionEditorProvider.cs index 47a2dcb7f..61ba5014e 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/ViewModels/SourceTreeTableDefinitionEditorProvider.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/ViewModels/SourceTreeTableDefinitionEditorProvider.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Newtonsoft.Json; +using WDE.Common; using WDE.Common.CoreVersion; using WDE.DatabaseEditors.Data.Structs; using WDE.Module.Attributes; @@ -55,7 +56,7 @@ private bool TryAdd(DirectoryInfo? root) } catch (Exception e) { - Console.WriteLine(e); + LOG.LogError(e); } } diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnView.axaml index 824c1b9b7..32b4f2ea1 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnView.axaml @@ -30,7 +30,7 @@ - an actual database column - a button that opens the conditions editor - a special button which meaning can be customized (meta column)">Column type: - + @@ -93,7 +93,7 @@ This will generate a comment, it will substitute `thisString.COLUMN` with a stri Column type: + ItemsSource="{CompiledBinding Parent.Parent.Parent.MetaColumnFactory.Types}"> diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnsView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnsView.axaml index 9920e5d65..f36937004 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnsView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/ColumnsView.axaml @@ -23,7 +23,7 @@ Foreign tables: - + @@ -51,7 +51,7 @@ Background="{DynamicResource ThemeBackgroundBrush}" BorderThickness="{DynamicResource ThemeBorderThickness}" BorderBrush="{DynamicResource ThemeBorderMidBrush}" - Items="{CompiledBinding Groups}" + ItemsSource="{CompiledBinding Groups}" SelectedItem="{CompiledBinding SelectedColumnOrGroup}"> diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/CommandView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/CommandView.axaml index 320e1c4ec..53bdda6ac 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/CommandView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/CommandView.axaml @@ -33,7 +33,7 @@ - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/CommandsView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/CommandsView.axaml index 7101883d6..48d11d64a 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/CommandsView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/CommandsView.axaml @@ -14,7 +14,7 @@ - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/ConditionsView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/ConditionsView.axaml index fdb33f348..7eeba290a 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/ConditionsView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/ConditionsView.axaml @@ -53,7 +53,7 @@ - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseColumnCompletionBox.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseColumnCompletionBox.cs index 72afbc434..ab25c7b77 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseColumnCompletionBox.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseColumnCompletionBox.cs @@ -16,12 +16,10 @@ namespace WDE.DatabaseDefinitionEditor.Views.Controls; -public class DatabaseColumnCompletionBox : CompletionComboBox, IStyleable +public class DatabaseColumnCompletionBox : CompletionComboBox { - Type IStyleable.StyleKey => typeof(CompletionComboBox); - public static readonly StyledProperty TableNameProperty = AvaloniaProperty.Register(nameof(TableName)); - //protected override Type StyleKeyOverride => typeof(CompletionComboBox); // avalonia 11 + protected override Type StyleKeyOverride => typeof(CompletionComboBox); public string? TableName { diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCommandCompletionBox.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCommandCompletionBox.cs index 4c21edc32..39c020b73 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCommandCompletionBox.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCommandCompletionBox.cs @@ -13,9 +13,9 @@ namespace WDE.DatabaseDefinitionEditor.Views.Controls; -public class DatabaseTableCommandCompletionBox : CompletionComboBox, IStyleable +public class DatabaseTableCommandCompletionBox : CompletionComboBox { - Type IStyleable.StyleKey => typeof(CompletionComboBox); + protected override Type StyleKeyOverride => typeof(CompletionComboBox); public string CommandId { diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCompletionBox.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCompletionBox.cs index 9cb98dc66..cb5ee8ff1 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCompletionBox.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/DatabaseTableCompletionBox.cs @@ -15,9 +15,9 @@ namespace WDE.DatabaseDefinitionEditor.Views.Controls; -public class DatabaseTableCompletionBox : CompletionComboBox, IStyleable +public class DatabaseTableCompletionBox : CompletionComboBox { - Type IStyleable.StyleKey => typeof(CompletionComboBox); + protected override Type StyleKeyOverride => typeof(CompletionComboBox); public static readonly DirectProperty TableNameProperty = AvaloniaProperty.RegisterDirect(nameof(TableName), o => o.TableName, (o, v) => o.TableName = v, defaultBindingMode: BindingMode.TwoWay); @@ -74,7 +74,7 @@ static DatabaseTableCompletionBox() private CancellationTokenSource? cts; public static readonly StyledProperty CanSelectEmptyProperty = - AvaloniaProperty.Register(nameof(CanSelectEmpty)); + AvaloniaProperty.Register(nameof(CanSelectEmpty)); public static readonly StyledProperty DatabaseProperty = AvaloniaProperty.Register("Database"); diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/KeyBindingBox.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/KeyBindingBox.cs index f4f3c3370..ff31b59ac 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/KeyBindingBox.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/KeyBindingBox.cs @@ -10,9 +10,9 @@ namespace WDE.DatabaseDefinitionEditor.Views.Controls; -public class TextBoxWithNoInput : TextBox, IStyleable +public class TextBoxWithNoInput : TextBox { - Type IStyleable.StyleKey => typeof(TextBox); + protected override Type StyleKeyOverride => typeof(TextBox); protected override void OnTextInput(TextInputEventArgs e) { @@ -85,7 +85,7 @@ private void Handler(object? sender, KeyEventArgs e) else if (e.Key == Key.LeftAlt || e.Key == Key.RightAlt) modifier &= ~KeyModifiers.Alt; - KeyGesture = new KeyGesture(e.Key, modifier); + SetCurrentValue(KeyGestureProperty, new KeyGesture(e.Key, modifier)); e.Handled = true; } } \ No newline at end of file diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/NullableDatabaseColumnCompletionBox.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/NullableDatabaseColumnCompletionBox.cs index c7c1d59f6..b67ae61fa 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/NullableDatabaseColumnCompletionBox.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/NullableDatabaseColumnCompletionBox.cs @@ -69,7 +69,7 @@ private void UpdateIsNull() return; inEvent = true; - IsNotNull = !string.IsNullOrWhiteSpace(columnName); + SetCurrentValue(IsNotNullProperty, !string.IsNullOrWhiteSpace(columnName)); inEvent = false; } diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/OnReleaseListBoxItem.cs b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/OnReleaseListBoxItem.cs index 2cdeaabfc..4d768efa9 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/OnReleaseListBoxItem.cs +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/Controls/OnReleaseListBoxItem.cs @@ -2,16 +2,21 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Styling; using Avalonia.VisualTree; namespace WDE.DatabaseDefinitionEditor.Views.Controls; -// note: in avalonia 11 this is not required. -// this changes the listbox to update the selection on pointer release rather than pointer press -public class OnReleaseListBox : ListBox, IStyleable +// this changes the listbox to update the selection on pointer release rather than pointer press (originally handled in ListBoxItem) +public class OnReleaseListBox : ListBox { - Type IStyleable.StyleKey => typeof(ListBox); + protected override Type StyleKeyOverride => typeof(ListBox); + + static OnReleaseListBox() + { + PointerPressedEvent.AddClassHandler((x, e) => x.OnPointerPressed(e), RoutingStrategies.Tunnel); + } protected override void OnPointerPressed(PointerPressedEventArgs e) { @@ -21,7 +26,7 @@ protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerReleased(Avalonia.Input.PointerReleasedEventArgs e) { base.OnPointerReleased(e); - if (e.Source is IVisual source) + if (e.Source is Visual source) { var point = e.GetCurrentPoint(source); @@ -30,8 +35,8 @@ protected override void OnPointerReleased(Avalonia.Input.PointerReleasedEventArg e.Handled = UpdateSelectionFromEventSource( e.Source, true, - e.KeyModifiers.HasAllFlags(KeyModifiers.Shift), - e.KeyModifiers.HasAllFlags(KeyModifiers.Control), + e.KeyModifiers.HasFlagFast(KeyModifiers.Shift), + e.KeyModifiers.HasFlagFast(KeyModifiers.Control), point.Properties.IsRightButtonPressed); } } diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionEditorView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionEditorView.axaml index c6f23a7ab..64880c3cc 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionEditorView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionEditorView.axaml @@ -17,7 +17,7 @@ Definitions: - @@ -34,7 +34,7 @@ Pick a table to import: - + @@ -45,15 +45,9 @@ - - - - - - - diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionToolView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionToolView.axaml index fe31848e1..5d3dc1204 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionToolView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionToolView.axaml @@ -20,7 +20,7 @@ Connected database tables: - @@ -43,7 +43,7 @@ All provided table definitions: - @@ -70,9 +70,9 @@ - + - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionView.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionView.axaml index 85c3a4349..d8bba96cd 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionView.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/DefinitionView.axaml @@ -13,7 +13,7 @@ x:DataType="definitionEditor:DefinitionViewModel"> Database: - + Table name: @@ -40,7 +40,7 @@ Table record mode: - + Friendly name: @@ -66,7 +66,7 @@ MultiRecord and SingleRow can be used for tables with multi (or single) column p IsVisible="{CompiledBinding IsSingleRow, Converter={x:Static BoolConverters.Not}}" /> Is only conditions table: - + Flags: @@ -89,7 +89,7 @@ MultiRecord and SingleRow can be used for tables with multi (or single) column p - + @@ -142,7 +142,7 @@ I.e. user looks for sound = 1423 and it finds row in the creature_text table wit - + @@ -169,7 +169,7 @@ I.e. user looks for sound = 1423 and it finds row in the creature_text table wit Auto key value: - diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/ForeignTables.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/ForeignTables.axaml index 9f9b368e3..fa027d852 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/ForeignTables.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/ForeignTables.axaml @@ -16,7 +16,7 @@ - + @@ -51,7 +51,7 @@ - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/Views/TemplateModePreview.axaml b/Modules/WDE.DatabaseDefinitionEditor/Views/TemplateModePreview.axaml index 700911838..1af2574b9 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/Views/TemplateModePreview.axaml +++ b/Modules/WDE.DatabaseDefinitionEditor/Views/TemplateModePreview.axaml @@ -8,7 +8,7 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:DataType="definitionEditor:DefinitionViewModel" x:Class="WDE.DatabaseDefinitionEditor.Views.TemplateModePreview"> - + @@ -27,7 +27,7 @@ VerticalAlignment="Center"/> - + diff --git a/Modules/WDE.DatabaseDefinitionEditor/WDE.DatabaseDefinitionEditor.csproj b/Modules/WDE.DatabaseDefinitionEditor/WDE.DatabaseDefinitionEditor.csproj index 3e4ad8f4f..0c216f9ed 100644 --- a/Modules/WDE.DatabaseDefinitionEditor/WDE.DatabaseDefinitionEditor.csproj +++ b/Modules/WDE.DatabaseDefinitionEditor/WDE.DatabaseDefinitionEditor.csproj @@ -1,12 +1,12 @@ - net7.0 + net8.0 Library false Debug;Release AnyCPU enable - nullable + $(WarningsAsErrors),nullable ..\bin\$(Configuration)\ diff --git a/Modules/WDE.DatabaseEditors.Test/Services/QueryParserServiceTests.cs b/Modules/WDE.DatabaseEditors.Test/Services/QueryParserServiceTests.cs index 5696cfda7..4b40a3028 100644 --- a/Modules/WDE.DatabaseEditors.Test/Services/QueryParserServiceTests.cs +++ b/Modules/WDE.DatabaseEditors.Test/Services/QueryParserServiceTests.cs @@ -19,7 +19,7 @@ namespace WDE.DatabaseEditors.Test.Services; public class QueryParserServiceTests { - private IQueryParserService parserService; + private IQueryParserService parserService = null!; [SetUp] public void Setup() @@ -67,7 +67,7 @@ public void Setup() dataLoader.Load(default!, default, default, default, default) .ReturnsForAnyArgs( - Task.FromResult(new DatabaseTableData(definition, new List() + Task.FromResult(new DatabaseTableData(definition, new List() { new DatabaseEntity(true, new DatabaseKey(0, 18675), new Dictionary(), null) }))); diff --git a/Modules/WDE.DatabaseEditors.Test/WDE.DatabaseEditors.Test.csproj b/Modules/WDE.DatabaseEditors.Test/WDE.DatabaseEditors.Test.csproj index dfc218580..d9e484b9b 100644 --- a/Modules/WDE.DatabaseEditors.Test/WDE.DatabaseEditors.Test.csproj +++ b/Modules/WDE.DatabaseEditors.Test/WDE.DatabaseEditors.Test.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 enable false @@ -10,9 +10,9 @@ - - - + + + diff --git a/Modules/WDE.Debugger.Test/Services/DebuggerServiceTests.cs b/Modules/WDE.Debugger.Test/Services/DebuggerServiceTests.cs index 3977b0db0..b4dc05105 100644 --- a/Modules/WDE.Debugger.Test/Services/DebuggerServiceTests.cs +++ b/Modules/WDE.Debugger.Test/Services/DebuggerServiceTests.cs @@ -647,11 +647,10 @@ public async Task EditorConnected_EventFired_ShouldSynchronizeAppropriateDebugPo }); bool exceptionSynchronizationAttempted = false; - source3.Synchronizer.Synchronize(exceptionDebugPointId).Returns(async _ => + source3.Synchronizer.Synchronize(exceptionDebugPointId).Returns>(async _ => { exceptionSynchronizationAttempted = true; throw new Exception("Synchronization failed."); - return SynchronizationResult.Ok; }); // Act diff --git a/Modules/WDE.Debugger.Test/WDE.Debugger.Test.csproj b/Modules/WDE.Debugger.Test/WDE.Debugger.Test.csproj index 839f84bd3..b60ef4de6 100644 --- a/Modules/WDE.Debugger.Test/WDE.Debugger.Test.csproj +++ b/Modules/WDE.Debugger.Test/WDE.Debugger.Test.csproj @@ -1,9 +1,9 @@ - net7.0 + net8.0 enable - nullable + $(WarningsAsErrors),nullable false @@ -11,9 +11,9 @@ - - - + + + diff --git a/Modules/WDE.Debugger/Services/DebuggerService.cs b/Modules/WDE.Debugger/Services/DebuggerService.cs index a69fa3baf..cde890eef 100644 --- a/Modules/WDE.Debugger/Services/DebuggerService.cs +++ b/Modules/WDE.Debugger/Services/DebuggerService.cs @@ -6,6 +6,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Prism.Events; +using WDE.Common; using WDE.Common.Debugging; using WDE.Common.Services; using WDE.Common.Utils; @@ -158,7 +159,7 @@ void LoadSnapshot(DebugPointSnapshot snapshot) { if (!sourcesByKey.TryGetValue(snapshot.SourceName, out var source)) { - Console.WriteLine("Couldn't deserialize debug point with key: " + snapshot.SourceName); + LOG.LogWarning("Couldn't deserialize debug point with key: " + snapshot.SourceName); return; } @@ -193,13 +194,13 @@ void LoadSnapshot(DebugPointSnapshot snapshot) } catch (Exception e) { - Console.WriteLine("Couldn't load a snapshot: " + e); + LOG.LogError(e, message: "Couldn't load a snapshot"); } } } catch (Exception e) { - Console.WriteLine("Couldn't load snapshots: " + e); + LOG.LogError(e, message: "Couldn't load snapshots"); } } @@ -256,7 +257,7 @@ private async Task SynchronizePointAndUpdateState(DebugPointModel debug) else throw new ArgumentOutOfRangeException(nameof(result)); } - catch (OperationCanceledException e) + catch (OperationCanceledException) { debug.State = BreakpointState.Pending; } @@ -669,11 +670,11 @@ public async Task Synchronize(DebugPointId id) await debug.Source.Synchronizer.Delete(id); debug.State = BreakpointState.Synced; } - catch (OperationCanceledException e) + catch (OperationCanceledException) { debug.State = BreakpointState.Pending; } - catch (Exception e) + catch (Exception) { debug.State = BreakpointState.SynchronizationError; throw; @@ -692,12 +693,12 @@ public async Task Synchronize(DebugPointId id) await debug.Source.Synchronizer.Delete(id); RemoveDebugPointInternal(id); } - catch (DebuggingFeaturesDisabledException e) + catch (DebuggingFeaturesDisabledException) { RemoveDebugPointInternal(id); throw; } - catch (Exception e) + catch (Exception) { debug.State = BreakpointState.SynchronizationError; CallDebugPointChangedInternal(id); diff --git a/Modules/WDE.Debugger/Views/Inspector/DebugPointsInspectorToolBar.axaml b/Modules/WDE.Debugger/Views/Inspector/DebugPointsInspectorToolBar.axaml index fcc51e14b..78a94bad5 100644 --- a/Modules/WDE.Debugger/Views/Inspector/DebugPointsInspectorToolBar.axaml +++ b/Modules/WDE.Debugger/Views/Inspector/DebugPointsInspectorToolBar.axaml @@ -10,7 +10,7 @@ - + diff --git a/Modules/WDE.SqlWorkbench/Views/DumpView.axaml b/Modules/WDE.SqlWorkbench/Views/DumpView.axaml index c232e9a2b..4f830638c 100644 --- a/Modules/WDE.SqlWorkbench/Views/DumpView.axaml +++ b/Modules/WDE.SqlWorkbench/Views/DumpView.axaml @@ -36,8 +36,7 @@ - @@ -76,7 +75,7 @@ - + diff --git a/Modules/WDE.SqlWorkbench/Views/SelectSingleTableView.axaml.cs b/Modules/WDE.SqlWorkbench/Views/SelectSingleTableView.axaml.cs index 8117d5cd5..f421d47a2 100644 --- a/Modules/WDE.SqlWorkbench/Views/SelectSingleTableView.axaml.cs +++ b/Modules/WDE.SqlWorkbench/Views/SelectSingleTableView.axaml.cs @@ -1,6 +1,7 @@ using System; using Avalonia; using Avalonia.Controls; +using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using Avalonia.Threading; @@ -87,7 +88,7 @@ private void VirtualizedVeryFastTableView_OnValueUpdateRequest(string newValue) } } - private void InputElement_OnDoubleTapped(object? sender, RoutedEventArgs e) + private void InputElement_OnDoubleTapped(object? sender, TappedEventArgs e) { if (DataContext is SelectSingleTableViewModel vm) { diff --git a/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchToolBar.axaml b/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchToolBar.axaml index 446de3b98..ba63720b8 100644 --- a/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchToolBar.axaml +++ b/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchToolBar.axaml @@ -40,7 +40,7 @@ - + diff --git a/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchView.axaml b/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchView.axaml index 294a8da74..df625a72e 100644 --- a/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchView.axaml +++ b/Modules/WDE.SqlWorkbench/Views/SqlWorkbenchView.axaml @@ -41,7 +41,7 @@ Change connection for this tab: - +