From 950838141e1aaff75a9508c3d9c47d6d584ac8d3 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 8 Aug 2023 16:40:01 -0400 Subject: [PATCH] Move prompt card to separate control --- StabilityMatrix.Avalonia/App.axaml | 1 + StabilityMatrix.Avalonia/App.axaml.cs | 11 +- .../Controls/PromptCard.axaml | 59 +++++++++ .../Controls/PromptCard.axaml.cs | 80 ++++++++++++ .../DesignData/DesignData.cs | 7 +- .../Inference/InferenceTextToImageModel.cs | 11 +- .../Models/Inference/PromptCardModel.cs | 10 ++ .../InferenceTextToImageViewModel.cs | 25 ++-- .../Inference/PromptCardViewModel.cs | 31 +++++ .../ViewModels/InferenceViewModel.cs | 14 +- .../Views/InferenceTextToImageView.axaml | 43 +------ .../Views/InferenceTextToImageView.axaml.cs | 120 +----------------- 12 files changed, 218 insertions(+), 194 deletions(-) create mode 100644 StabilityMatrix.Avalonia/Controls/PromptCard.axaml create mode 100644 StabilityMatrix.Avalonia/Controls/PromptCard.axaml.cs create mode 100644 StabilityMatrix.Avalonia/Models/Inference/PromptCardModel.cs create mode 100644 StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs diff --git a/StabilityMatrix.Avalonia/App.axaml b/StabilityMatrix.Avalonia/App.axaml index c820f7c8..6277e18c 100644 --- a/StabilityMatrix.Avalonia/App.axaml +++ b/StabilityMatrix.Avalonia/App.axaml @@ -31,5 +31,6 @@ + diff --git a/StabilityMatrix.Avalonia/App.axaml.cs b/StabilityMatrix.Avalonia/App.axaml.cs index d3f4135c..5a04fa86 100644 --- a/StabilityMatrix.Avalonia/App.axaml.cs +++ b/StabilityMatrix.Avalonia/App.axaml.cs @@ -248,15 +248,18 @@ public sealed class App : Application services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); // Global progress services.AddSingleton(); // Controls services.AddTransient(); + + // Inference controls + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // Dialog factory services.AddSingleton>(provider => @@ -277,6 +280,7 @@ public sealed class App : Application .Register(provider.GetRequiredService) .Register(provider.GetRequiredService) .Register(provider.GetRequiredService) + .Register(provider.GetRequiredService) .Register(provider.GetRequiredService)); } @@ -298,6 +302,7 @@ public sealed class App : Application services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); // Dialogs services.AddTransient(); diff --git a/StabilityMatrix.Avalonia/Controls/PromptCard.axaml b/StabilityMatrix.Avalonia/Controls/PromptCard.axaml new file mode 100644 index 00000000..89c2dfff --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/PromptCard.axaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Controls/PromptCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/PromptCard.axaml.cs new file mode 100644 index 00000000..b0b00f60 --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/PromptCard.axaml.cs @@ -0,0 +1,80 @@ +using System.IO; +using System.Reflection; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Media; +using AvaloniaEdit; +using AvaloniaEdit.TextMate; +using StabilityMatrix.Avalonia.Extensions; +using TextMateSharp.Grammars; +using TextMateSharp.Internal.Themes.Reader; +using TextMateSharp.Registry; +using TextMateSharp.Themes; + +namespace StabilityMatrix.Avalonia.Controls; + +public class PromptCard : TemplatedControl +{ + /// + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + + InitializeEditors(e); + } + + private static IRawTheme GetThemeFromStream(Stream stream) + { + using var reader = new StreamReader(stream); + return ThemeReader.ReadThemeSync(reader); + } + + private static IRawTheme GetCustomTheme() + { + using var stream = Assets.ThemeMatrixDarkJson.Open(); + return GetThemeFromStream(stream); + } + + private void InitializeEditors(TemplateAppliedEventArgs e) + { + const ThemeName themeName = ThemeName.DimmedMonokai; + var registryOptions = new RegistryOptions(themeName); + + var registry = new Registry(registryOptions); + + using var stream = Assets.ImagePromptLanguageJson.Open(); + var promptGrammar = registry.LoadGrammarFromStream(stream); + + // Load theme + var theme = GetCustomTheme(); + + foreach (var editor in new[] + { + e.NameScope.Find("PromptEditor"), + e.NameScope.Find("NegativePromptEditor") + }) + { + if (editor is not null) + { + var editorOptions = editor.Options; + editorOptions.ShowColumnRulers = true; + editorOptions.EnableTextDragDrop = true; + editorOptions.ExtendSelectionOnMouseUp = true; + // Config hyperlinks + editorOptions.EnableHyperlinks = true; + editorOptions.RequireControlModifierForHyperlinkClick = true; + editor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Coral; + + var installation = editor.InstallTextMate(registryOptions); + + // Set the _textMateRegistry property + var field = typeof(TextMate.Installation).GetField("_textMateRegistry", BindingFlags.Instance | BindingFlags.NonPublic); + field!.SetValue(installation, registry); + + installation.SetGrammar(promptGrammar.GetScopeName()); + + installation.SetTheme(theme); + } + } + } +} diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index 66ee4fa5..f84023c9 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -392,8 +392,11 @@ public static class DesignData }); }); -public static Indexer Types => new(); - + public static PromptCardViewModel PromptCardViewModel => + DialogFactory.Get(); + + public static Indexer Types => new(); + public class Indexer { public object? this[string typeName] diff --git a/StabilityMatrix.Avalonia/Models/Inference/InferenceTextToImageModel.cs b/StabilityMatrix.Avalonia/Models/Inference/InferenceTextToImageModel.cs index f5e3cf92..df9ddaa2 100644 --- a/StabilityMatrix.Avalonia/Models/Inference/InferenceTextToImageModel.cs +++ b/StabilityMatrix.Avalonia/Models/Inference/InferenceTextToImageModel.cs @@ -5,9 +5,10 @@ namespace StabilityMatrix.Avalonia.Models.Inference; [JsonSerializable(typeof(InferenceTextToImageModel))] public class InferenceTextToImageModel { - public string? Prompt { get; set; } - public string? NegativePrompt { get; set; } - public string? SelectedModelName { get; set; } - public SeedCardModel? SeedCardState { get; set; } - public SamplerCardModel? SamplerCardState { get; set; } + public string? Prompt { get; init; } + public string? NegativePrompt { get; init; } + public string? SelectedModelName { get; init; } + public SeedCardModel? SeedCardState { get; init; } + public SamplerCardModel? SamplerCardState { get; init; } + public PromptCardModel? PromptCardState { get; init; } } diff --git a/StabilityMatrix.Avalonia/Models/Inference/PromptCardModel.cs b/StabilityMatrix.Avalonia/Models/Inference/PromptCardModel.cs new file mode 100644 index 00000000..22029c30 --- /dev/null +++ b/StabilityMatrix.Avalonia/Models/Inference/PromptCardModel.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace StabilityMatrix.Avalonia.Models.Inference; + +[JsonSerializable(typeof(PromptCardModel))] +public class PromptCardModel +{ + public string? Prompt { get; set; } + public string? NegativePrompt { get; set; } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index 7b981840..2cf4bc4b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -18,7 +18,6 @@ using StabilityMatrix.Avalonia.Models.Inference; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.Views; using StabilityMatrix.Core.Attributes; -using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Models.Api.Comfy; using StabilityMatrix.Core.Models.Api.Comfy.WebSocketData; @@ -40,11 +39,7 @@ public partial class InferenceTextToImageViewModel public SamplerCardViewModel SamplerCardViewModel { get; } public SamplerCardViewModel HiresFixSamplerCardViewModel { get; } public ImageGalleryCardViewModel ImageGalleryCardViewModel { get; } - - public InferenceViewModel? Parent { get; set; } - - public TextDocument PromptDocument { get; } = new(); - public TextDocument NegativePromptDocument { get; } = new(); + public PromptCardViewModel PromptCardViewModel { get; } [ObservableProperty] private string? selectedModelName; @@ -81,6 +76,7 @@ public partial class InferenceTextToImageViewModel vm.IsDenoiseStrengthEnabled = true; }); ImageGalleryCardViewModel = vmFactory.Get(); + PromptCardViewModel = vmFactory.Get(); SeedCardViewModel.GenerateNewSeed(); } @@ -127,7 +123,7 @@ public partial class InferenceTextToImageViewModel Inputs = new Dictionary { ["clip"] = new object[] { "4", 1 }, - ["text"] = PromptDocument.Text, + ["text"] = PromptCardViewModel.PromptDocument.Text, } }, ["7"] = new() @@ -136,7 +132,7 @@ public partial class InferenceTextToImageViewModel Inputs = new Dictionary { ["clip"] = new object[] { "4", 1 }, - ["text"] = NegativePromptDocument.Text, + ["text"] = PromptCardViewModel.NegativePromptDocument.Text, } }, ["8"] = new() @@ -198,7 +194,6 @@ public partial class InferenceTextToImageViewModel var nodes = GetCurrentPrompt(); // Connect progress handler - OutputProgress.IsIndeterminate = true; client.ProgressUpdateReceived += OnProgressUpdateReceived; client.PreviewImageReceived += OnPreviewImageReceived; @@ -265,6 +260,7 @@ public partial class InferenceTextToImageViewModel { // Disconnect progress handler OutputProgress.Value = 0; + ImageGalleryCardViewModel.PreviewImage?.Dispose(); ImageGalleryCardViewModel.PreviewImage = null; ImageGalleryCardViewModel.IsPreviewOverlayEnabled = false; client.ProgressUpdateReceived -= OnProgressUpdateReceived; @@ -288,8 +284,6 @@ public partial class InferenceTextToImageViewModel /// public void LoadState(InferenceTextToImageModel state) { - PromptDocument.Text = state.Prompt; - NegativePromptDocument.Text = state.NegativePrompt; SelectedModelName = state.SelectedModelName; if (state.SeedCardState != null) @@ -300,6 +294,10 @@ public partial class InferenceTextToImageViewModel { SamplerCardViewModel.LoadState(state.SamplerCardState); } + if (state.PromptCardState != null) + { + PromptCardViewModel.LoadState(state.PromptCardState); + } } /// @@ -307,11 +305,10 @@ public partial class InferenceTextToImageViewModel { return new InferenceTextToImageModel { - Prompt = PromptDocument.Text, - NegativePrompt = NegativePromptDocument.Text, SelectedModelName = SelectedModelName, SeedCardState = SeedCardViewModel.SaveState(), - SamplerCardState = SamplerCardViewModel.SaveState() + SamplerCardState = SamplerCardViewModel.SaveState(), + PromptCardState = PromptCardViewModel.SaveState(), }; } } diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs new file mode 100644 index 00000000..9f41040e --- /dev/null +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/PromptCardViewModel.cs @@ -0,0 +1,31 @@ +using AvaloniaEdit.Document; +using StabilityMatrix.Avalonia.Controls; +using StabilityMatrix.Avalonia.Models; +using StabilityMatrix.Avalonia.Models.Inference; +using StabilityMatrix.Core.Attributes; + +namespace StabilityMatrix.Avalonia.ViewModels.Inference; + +[View(typeof(PromptCard))] +public class PromptCardViewModel : ViewModelBase, ILoadableState +{ + public TextDocument PromptDocument { get; } = new(); + public TextDocument NegativePromptDocument { get; } = new(); + + /// + public void LoadState(PromptCardModel state) + { + PromptDocument.Text = state.Prompt ?? ""; + NegativePromptDocument.Text = state.NegativePrompt ?? ""; + } + + /// + public PromptCardModel SaveState() + { + return new PromptCardModel + { + Prompt = PromptDocument.Text, + NegativePrompt = NegativePromptDocument.Text + }; + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs index 2d5746dd..c2b6ac21 100644 --- a/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/InferenceViewModel.cs @@ -80,19 +80,11 @@ public partial class InferenceViewModel : PageViewModelBase }; } - private InferenceTextToImageViewModel CreateTextToImageViewModel() - { - return vmFactory.Get(vm => - { - vm.Parent = this; - }); - } - public override void OnLoaded() { if (Tabs.Count == 0) { - Tabs.Add(CreateTextToImageViewModel()); + AddTab(); } // Select first tab if none is selected @@ -110,7 +102,7 @@ public partial class InferenceViewModel : PageViewModelBase [RelayCommand] private void AddTab() { - Tabs.Add(CreateTextToImageViewModel()); + Tabs.Add(vmFactory.Get()); } /// @@ -276,7 +268,7 @@ public partial class InferenceViewModel : PageViewModelBase ViewModelBase? vm = null; if (document.ProjectType is InferenceProjectType.TextToImage) { - var textToImage = CreateTextToImageViewModel(); + var textToImage = vmFactory.Get(); textToImage.LoadState(document.State.Deserialize()!); vm = textToImage; } diff --git a/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml b/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml index f5f5de0a..f5a45731 100644 --- a/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml +++ b/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml @@ -140,47 +140,10 @@ Grid.Row="0" Grid.Column="2" Margin="8,8,8,16" - Grid.RowDefinitions="*,Auto"> + RowDefinitions="*,Auto"> - - - - - - - - - + diff --git a/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml.cs b/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml.cs index 6dd4eec6..bcc4f2be 100644 --- a/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml.cs +++ b/StabilityMatrix.Avalonia/Views/InferenceTextToImageView.axaml.cs @@ -1,26 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Xml; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Markup.Xaml; -using Avalonia.Media; -using AvaloniaEdit; -using AvaloniaEdit.Highlighting; -using AvaloniaEdit.Highlighting.Xshd; -using AvaloniaEdit.TextMate; -using Markdown.Avalonia.SyntaxHigh.Extensions; +using Avalonia.Markup.Xaml; using StabilityMatrix.Avalonia.Controls; -using StabilityMatrix.Avalonia.Extensions; -using TextMateSharp.Grammars; -using TextMateSharp.Internal.Grammars.Reader; -using TextMateSharp.Internal.Themes.Reader; -using TextMateSharp.Internal.Types; -using TextMateSharp.Registry; -using TextMateSharp.Themes; namespace StabilityMatrix.Avalonia.Views; @@ -35,101 +14,4 @@ public partial class InferenceTextToImageView : UserControlBase { AvaloniaXamlLoader.Load(this); } - - /// - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - InitializeEditors(); - } - - private static IRawTheme GetThemeFromStream(Stream stream) - { - using var reader = new StreamReader(stream); - return ThemeReader.ReadThemeSync(reader); - } - - private static IRawTheme GetCustomTheme() - { - using var stream = Assets.ThemeMatrixDarkJson.Open(); - return GetThemeFromStream(stream); - } - - private void InitializeEditors() - { - const ThemeName themeName = ThemeName.DimmedMonokai; - var registryOptions = new RegistryOptions(themeName); - - var registry = new Registry(registryOptions); - - using var stream = Assets.ImagePromptLanguageJson.Open(); - var promptGrammar = registry.LoadGrammarFromStream(stream); - - // Load theme - var theme = GetCustomTheme(); - - foreach (var editor in new[] - { - this.FindControl("PromptEditor"), - this.FindControl("NegativePromptEditor") - }) - { - if (editor is not null) - { - var editorOptions = editor.Options; - editorOptions.ShowColumnRulers = true; - editorOptions.EnableTextDragDrop = true; - editorOptions.ExtendSelectionOnMouseUp = true; - // Config hyperlinks - editorOptions.EnableHyperlinks = true; - editorOptions.RequireControlModifierForHyperlinkClick = true; - editor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Coral; - - var installation = editor.InstallTextMate(registryOptions); - - // Set the _textMateRegistry property - var field = typeof(TextMate.Installation).GetField("_textMateRegistry", BindingFlags.Instance | BindingFlags.NonPublic); - field!.SetValue(installation, registry); - - installation.SetGrammar(promptGrammar.GetScopeName()); - - installation.SetTheme(theme); - } - } - } - - /*private void InitializeEditorsForXshd() - { - var highlightManager = HighlightingManager.Instance; - - using var stream = Assets.SDPromptXshd.Open(); - using var reader = new XmlTextReader(stream); - - highlightManager.RegisterHighlighting( - "ImagePrompt", - new []{ ".prompt" }, - HighlightingLoader.Load(reader, HighlightingManager.Instance)); - - const ThemeName theme = ThemeName.DimmedMonokai; - - foreach (var editor in new[] - { - this.FindControl("PromptEditor"), - this.FindControl("NegativePromptEditor") - }) - { - if (editor is not null) - { - var editorOptions = editor.TextArea.Options; - // Config hyperlinks - editorOptions.EnableHyperlinks = true; - editorOptions.RequireControlModifierForHyperlinkClick = true; - editor.TextArea.TextView.LinkTextForegroundBrush = Brushes.Coral; - - editor.SyntaxHighlighting = highlightManager.GetDefinition("ImagePrompt"); - } - } - }*/ - - }