Browse Source

Ported CommandDebugPopup

Krzysztof Krysiński 1 year ago
parent
commit
fa77e7529a

+ 23 - 0
src/PixiEditor.AvaloniaUI/Helpers/Converters/EmptyStringFillerConverter.cs

@@ -0,0 +1,23 @@
+using System.Globalization;
+using PixiEditor.UI.Common.Converters;
+
+namespace PixiEditor.AvaloniaUI.Helpers.Converters;
+internal class EmptyStringFillerConverter : MarkupConverter
+{
+    public string NullText { get; set; } = "[null]";
+
+    public string EmptyText { get; set; } = "[empty]";
+
+    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+    {
+        return value switch
+        {
+            string s => s.Length switch
+            {
+                0 => EmptyText,
+                _ => s
+            },
+            _ => NullText
+        };
+    }
+}

+ 2 - 4
src/PixiEditor.AvaloniaUI/ViewModels/SubViewModels/DebugViewModel.cs

@@ -13,6 +13,7 @@ using PixiEditor.AvaloniaUI.Models.Commands.Attributes.Commands;
 using PixiEditor.AvaloniaUI.Models.Commands.Templates.Providers.Parsers;
 using PixiEditor.AvaloniaUI.Models.Dialogs;
 using PixiEditor.AvaloniaUI.Views;
+using PixiEditor.AvaloniaUI.Views.Dialogs.Debugging;
 using PixiEditor.AvaloniaUI.Views.Dialogs.Debugging.Localization;
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.Common.UserPreferences;
@@ -216,10 +217,7 @@ internal class DebugViewModel : SubViewModel<ViewModelMain>
     [Command.Debug("PixiEditor.Debug.OpenCommandDebugWindow", "OPEN_CMD_DEBUG_WINDOW", "OPEN_CMD_DEBUG_WINDOW")]
     public void OpenCommandDebugWindow()
     {
-        //TODO: Fix this and implement CommandDebugPopup
-        //Mouse.OverrideCursor = Cursors.Wait;
-        //new CommandDebugPopup().Show();
-        //Mouse.OverrideCursor = null;
+        new CommandDebugPopup().Show();
     }
 
     [Command.Debug("PixiEditor.Debug.OpenLocalizationDebugWindow", "OPEN_LOCALIZATION_DEBUG_WINDOW", "OPEN_LOCALIZATION_DEBUG_WINDOW")]

+ 6 - 2
src/PixiEditor.AvaloniaUI/ViewModels/SubViewModels/LayersViewModel.cs

@@ -7,7 +7,9 @@ using Avalonia.Controls.ApplicationLifetimes;
 using Avalonia.Input;
 using Avalonia.Media;
 using Avalonia.Media.Imaging;
+using Avalonia.Platform;
 using Avalonia.Platform.Storage;
+using PixiEditor.AvaloniaUI.Helpers.Converters;
 using PixiEditor.AvaloniaUI.Helpers.Extensions;
 using PixiEditor.AvaloniaUI.Models.Commands.Attributes.Commands;
 using PixiEditor.AvaloniaUI.Models.Commands.Attributes.Evaluators;
@@ -429,8 +431,10 @@ internal class LayersViewModel : SubViewModel<ViewModelMain>
     {
         var doc = Owner.DocumentManagerSubViewModel.ActiveDocument;
         if (doc is null || doc.ReferenceLayerViewModel.IsTopMost)
-            return new Bitmap("pack://application:,,,/Images/ReferenceLayerBelow.png");
+        {
+            return ImagePathToBitmapConverter.LoadBitmapFromRelativePath("/Images/ReferenceLayerBelow.png");
+        }
 
-        return new Bitmap("pack://application:,,,/Images/ReferenceLayerAbove.png");
+        return ImagePathToBitmapConverter.LoadBitmapFromRelativePath("/Images/ReferenceLayerAbove.png");
     }
 }

+ 70 - 0
src/PixiEditor.AvaloniaUI/Views/Dialogs/Debugging/CommandDebugPopup.axaml

@@ -0,0 +1,70 @@
+<dialogs:PixiEditorPopup xmlns="https://github.com/avaloniaui"
+                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                         xmlns:dialogs="clr-namespace:PixiEditor.AvaloniaUI.Views.Dialogs"
+                         xmlns:converters="clr-namespace:PixiEditor.AvaloniaUI.Helpers.Converters"
+                         xmlns:xaml="clr-namespace:PixiEditor.AvaloniaUI.Models.Commands.XAML"
+                         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+                         Width="600" Height="400"
+                         x:Class="PixiEditor.AvaloniaUI.Views.Dialogs.Debugging.CommandDebugPopup"
+                         Name="uc"
+                         Title="CommandDebugPopup">
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition />
+        </Grid.RowDefinitions>
+
+        <StackPanel Orientation="Horizontal" Margin="5">
+            <Button Content="Export list"
+                    Command="{xaml:Command PixiEditor.Debug.DumpAllCommands}" Width="100" />
+        </StackPanel>
+
+        <ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="1">
+            <ItemsControl ItemsSource="{Binding Commands, ElementName=uc}" Margin="5,0,0,5">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <VirtualizingStackPanel/>
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <Border BorderThickness="0,0,0,1" BorderBrush="{DynamicResource ThemeBackgroundBrush1}">
+                            <Grid Margin="0,5,0,5">
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition Width="35" />
+                                    <ColumnDefinition />
+                                    <ColumnDefinition />
+                                    <ColumnDefinition />
+                                </Grid.ColumnDefinitions>
+                                <Grid.RowDefinitions>
+                                    <RowDefinition />
+                                    <RowDefinition />
+                                    <RowDefinition />
+                                </Grid.RowDefinitions>
+
+                                <Image Grid.RowSpan="3" Source="{Binding Image}" Margin="0,0,5,0" />
+
+                                <TextBlock Text="{Binding Command.InternalName}" Grid.Column="1" />
+                                <TextBlock
+                                    Text="{Binding Command.DisplayName, Converter={converters:EmptyStringFillerConverter EmptyText='[internal]', NullText='[internal]'}}"
+                                    Grid.Column="2" />
+                                <TextBlock
+                                    Text="{Binding Command.Description, Converter={converters:EmptyStringFillerConverter}}"
+                                    Grid.Column="3" />
+
+                                <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Command.DefaultShortcut, StringFormat=Default Shortcut: {0}}"/>
+                                <TextBlock Grid.Row="1" Grid.Column="2" Text="{Binding Command.Shortcut, StringFormat=Current Shortcut: {0}}"/>
+                                <TextBlock Grid.Row="1" Grid.Column="3" Text="{Binding Command.IsDebug, StringFormat=Is Debug: {0}}"/>
+
+                                <ContentControl Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3"
+                                                Content="{Binding Comments}" />
+                            </Grid>
+                        </Border>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+        </ScrollViewer>
+    </Grid>
+</dialogs:PixiEditorPopup>

+ 137 - 0
src/PixiEditor.AvaloniaUI/Views/Dialogs/Debugging/CommandDebugPopup.axaml.cs

@@ -0,0 +1,137 @@
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Documents;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+using PixiEditor.AvaloniaUI.Models.Commands;
+using PixiEditor.AvaloniaUI.Models.Commands.Commands;
+using PixiEditor.AvaloniaUI.Models.Commands.Evaluators;
+using PixiEditor.AvaloniaUI.ViewModels;
+
+namespace PixiEditor.AvaloniaUI.Views.Dialogs.Debugging;
+
+public partial class CommandDebugPopup : PixiEditorPopup
+{
+    private static Brush infoBrush = new SolidColorBrush(Color.FromRgb(129, 143, 156));
+
+    private static Brush warningBrush = new SolidColorBrush(Color.FromRgb(222, 130, 55));
+
+    private static Brush errorBrush = new SolidColorBrush(Color.FromRgb(230, 34, 57));
+
+    internal static readonly StyledProperty<IEnumerable<CommandDebug>> CommandsProperty = AvaloniaProperty.Register<CommandDebugPopup, IEnumerable<CommandDebug>>(
+        "Commands");
+
+    internal IEnumerable<CommandDebug> Commands
+    {
+        get => GetValue(CommandsProperty);
+        set => SetValue(CommandsProperty, value);
+    }
+
+    public CommandDebugPopup()
+    {
+        var debugCommands = new List<CommandDebug>();
+
+        foreach (var command in CommandController.Current.Commands)
+        {
+            var comments = new TextBlock { TextWrapping = TextWrapping.Wrap };
+
+            IImage? image = null;
+            Exception imageException = null;
+
+            try
+            {
+                image = command.IconEvaluator.CallEvaluate(command, null);
+            }
+            catch (Exception e)
+            {
+                imageException = e;
+            }
+
+            var analysis = AnalyzeCommand(command, image, imageException, out int issues);
+
+            foreach (var inline in analysis)
+            {
+                comments.Inlines.Add(inline);
+            }
+
+            debugCommands.Add(new CommandDebug(command, comments, image, issues));
+        }
+
+        Commands = debugCommands.OrderByDescending(x => x.Issues).ThenBy(x => x.Command.InternalName).ToArray();
+
+        InitializeComponent();
+    }
+
+    private List<Inline> AnalyzeCommand(Command command, IImage? image, Exception? imageException, out int issues)
+    {
+        var inlines = new List<Inline>();
+        issues = 0;
+
+        if (imageException != null)
+        {
+            Error($"Icon evaluator throws exception\n{imageException}\n");
+            issues++;
+        }
+        else
+        {
+            if (image == null && command.IconEvaluator == IconEvaluator.Default)
+            {
+                var expected = IconEvaluator.GetDefaultPath(command);
+
+                if (string.IsNullOrWhiteSpace(command.IconPath))
+                {
+                    Info(
+                        $"Default evaluator has not found a image (No icon path provided). Expected at '{expected}'\n");
+                }
+                else
+                {
+                    Error($"Default evaluator has not found a image at icon path! Expected at '{expected}'.\n");
+                    issues++;
+                }
+            }
+        }
+
+        if (command.IconEvaluator == null)
+        {
+            Warning("Icon evaluator is null");
+        }
+        else if (command.IconEvaluator != IconEvaluator.Default)
+        {
+            Info($"Uses custom icon evaluator ({command.IconEvaluator.Name})\n");
+        }
+
+        if (!string.IsNullOrWhiteSpace(command.IconPath))
+        {
+            Info($"Has custom icon path: '{command.IconPath}'\n");
+        }
+
+        return inlines;
+
+        void Info(string text) => inlines.Add(new Run(text) { Foreground = infoBrush });
+
+        void Warning(string text) => inlines.Add(new Run(text) { Foreground = warningBrush });
+
+        void Error(string text) => inlines.Add(new Run(text) { Foreground = errorBrush });
+    }
+
+    internal class CommandDebug
+    {
+        public Command Command { get; }
+
+        public TextBlock Comments { get; }
+
+        public IImage Image { get; }
+
+        public int Issues { get; }
+
+        public CommandDebug(Command command, TextBlock comments, IImage image, int issues)
+        {
+            Command = command;
+            Comments = comments;
+            Image = image;
+            Issues = issues;
+        }
+    }
+}