Browse Source

Added axes

Krzysztof Krysiński 3 months ago
parent
commit
64fdd6abe1

+ 1 - 1
samples/Sample7_FlyUI/Sample7_FlyUI.csproj

@@ -6,7 +6,7 @@
         <PublishTrimmed>true</PublishTrimmed>
         <WasmSingleFileBundle>true</WasmSingleFileBundle>
         <GenerateExtensionPackage>true</GenerateExtensionPackage>
-        <PixiExtOutputPath>..\..\src\PixiEditor.Desktop\bin\Debug\net8.0\win-x64\Extensions</PixiExtOutputPath>
+        <PixiExtOutputPath>..\..\src\PixiEditor.Desktop\bin\Debug\net8.0\Extensions</PixiExtOutputPath>
         <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
         <ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
         <RootNamespace>FlyUISample</RootNamespace>

+ 37 - 29
samples/Sample7_FlyUI/WindowContentElement.cs

@@ -1,47 +1,55 @@
-using PixiEditor.Extensions.CommonApi.FlyUI.Properties;
+using System.Diagnostics.CodeAnalysis;
+using PixiEditor.Extensions.CommonApi.FlyUI.Properties;
 using PixiEditor.Extensions.Sdk;
 using PixiEditor.Extensions.Sdk.Api.FlyUI;
 using PixiEditor.Extensions.Sdk.Api.Window;
 
 namespace FlyUISample;
 
+[SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:Parameter should not span multiple lines", Justification = "FlyUI style")]
 public class WindowContentElement : StatelessElement
 {
     public PopupWindow Window { get; set; }
+
     public override CompiledControl BuildNative()
     {
         Layout layout = new Layout(body:
             new Container(margin: Edges.All(25), child:
                 new Column(
-                    new Center(
-                        new Text(
-                            "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae neque nibh. Duis sed pharetra dolor. Donec dui sapien, aliquam id sodales in, ornare et urna. Mauris nunc odio, sagittis eget lectus at, imperdiet ornare quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod pellentesque blandit. Vestibulum sagittis, ligula non finibus lobortis, dolor lacus consectetur turpis, id facilisis ligula dolor vitae augue.",
-                            wrap: TextWrap.Wrap,
-                            fontSize: 16)
-                    ),
-                    new Align(
-                        alignment: Alignment.CenterRight,
-                        child: new Text("- Paulo Coelho, The Alchemist (1233)", fontStyle: FontStyle.Italic)
-                    ),
-                    new Container(
-                        margin: Edges.Symmetric(25, 0),
-                        backgroundColor: Color.FromRgba(25, 25, 25, 255),
-                        child: new Column(
-                            new Image(
-                                "/Pizza.png",
-                                filterQuality: FilterQuality.None,
-                                width: 256, height: 256))
-                    ),
-                    new CheckBox(new Text("heloo"), onCheckedChanged: args =>
-                    {
-                        PixiEditorExtension.Api.Logger.Log(((CheckBox)args.Sender).IsChecked ? "Checked" : "Unchecked");
-                    }),
-                    new Center(
-                        new Button(
-                            child: new Text("Close"), onClick: _ =>
+                    crossAxisAlignment: CrossAxisAlignment.Center,
+                    mainAxisAlignment: MainAxisAlignment.SpaceEvenly,
+                    children:
+                    [
+                        new Center(
+                            new Text(
+                                "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae neque nibh. Duis sed pharetra dolor. Donec dui sapien, aliquam id sodales in, ornare et urna. Mauris nunc odio, sagittis eget lectus at, imperdiet ornare quam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam euismod pellentesque blandit. Vestibulum sagittis, ligula non finibus lobortis, dolor lacus consectetur turpis, id facilisis ligula dolor vitae augue.",
+                                wrap: TextWrap.Wrap,
+                                fontSize: 16)
+                        ),
+                        new Align(
+                            alignment: Alignment.CenterRight,
+                            child: new Text("- Paulo Coelho, The Alchemist (1233)", fontStyle: FontStyle.Italic)
+                        ),
+                        new Container(
+                            margin: Edges.Symmetric(25, 0),
+                            backgroundColor: Color.FromRgba(25, 25, 25, 255),
+                            child: new Column(
+                                new Image(
+                                    "/Pizza.png",
+                                    filterQuality: FilterQuality.None,
+                                    width: 256, height: 256))
+                        ),
+                        new CheckBox(new Text("heloo"),
+                            onCheckedChanged: args =>
                             {
-                                Window.Close();
-                            }))
+                                PixiEditorExtension.Api.Logger.Log(((CheckBox)args.Sender).IsChecked
+                                    ? "Checked"
+                                    : "Unchecked");
+                            }),
+                        new Center(
+                            new Button(
+                                child: new Text("Close"), onClick: _ => { Window.Close(); }))
+                    ]
                 )
             )
         );

+ 18 - 0
src/PixiEditor.Extensions.Sdk/Api/FlyUI/AxisAlignment.cs

@@ -0,0 +1,18 @@
+namespace PixiEditor.Extensions.Sdk.Api.FlyUI;
+
+public enum MainAxisAlignment
+{
+    Start,
+    Center,
+    End,
+    SpaceBetween,
+    SpaceAround,
+    SpaceEvenly
+}
+
+public enum CrossAxisAlignment
+{
+    Start,
+    Center,
+    End
+}

+ 18 - 1
src/PixiEditor.Extensions.Sdk/Api/FlyUI/Column.cs

@@ -2,14 +2,31 @@
 
 public class Column : MultiChildLayoutElement
 {
+    public MainAxisAlignment MainAxisAlignment { get; set; }
+    public CrossAxisAlignment CrossAxisAlignment { get; set; }
+
+    public Column(
+        MainAxisAlignment mainAxisAlignment = MainAxisAlignment.Start,
+        CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start,
+        LayoutElement[] children = null)
+    {
+        MainAxisAlignment = mainAxisAlignment;
+        CrossAxisAlignment = crossAxisAlignment;
+        Children = new List<LayoutElement>(children);
+    }
+
     public Column(params LayoutElement[] children)
     {
+        MainAxisAlignment = MainAxisAlignment.Start;
+        CrossAxisAlignment = CrossAxisAlignment.Start;
         Children = new List<LayoutElement>(children);
     }
-    
+
     public override CompiledControl BuildNative()
     {
         CompiledControl control = new CompiledControl(UniqueId, "Column");
+        control.AddProperty(MainAxisAlignment);
+        control.AddProperty(CrossAxisAlignment);
         control.Children.AddRange(Children.Where(x => x != null).Select(x => x.BuildNative()));
 
         return control;

+ 18 - 1
src/PixiEditor.Extensions.Sdk/Api/FlyUI/Row.cs

@@ -2,14 +2,31 @@
 
 public class Row : MultiChildLayoutElement
 {
+    public MainAxisAlignment MainAxisAlignment { get; set; }
+    public CrossAxisAlignment CrossAxisAlignment { get; set; }
+
     public Row(params LayoutElement[] children)
     {
         Children = new List<LayoutElement>(children);
+        MainAxisAlignment = MainAxisAlignment.Start;
+        CrossAxisAlignment = CrossAxisAlignment.Start;
+    }
+
+    public Row(
+        MainAxisAlignment mainAxisAlignment = MainAxisAlignment.Start,
+        CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start,
+        LayoutElement[] children = null)
+    {
+        MainAxisAlignment = mainAxisAlignment;
+        CrossAxisAlignment = crossAxisAlignment;
+        Children = new List<LayoutElement>(children);
     }
-    
+
     public override CompiledControl BuildNative()
     {
         CompiledControl control = new CompiledControl(UniqueId, "Row");
+        control.AddProperty(MainAxisAlignment);
+        control.AddProperty(CrossAxisAlignment);
         control.Children.AddRange(Children.Select(x => x.BuildNative()));
 
         return control;

+ 1 - 1
src/PixiEditor.Extensions.Sdk/Api/Window/WindowProvider.cs

@@ -17,7 +17,7 @@ public class WindowProvider : IWindowProvider
         Marshal.FreeHGlobal(ptr);
         
         SubscribeToEvents(compiledControl);
-        return new PopupWindow(handle) { Title = title };
+        return new PopupWindow(handle);
     }
 
     internal void LayoutStateChanged(int uniqueId, CompiledControl newLayout)

+ 5 - 2
src/PixiEditor.Extensions.WasmRuntime/Api/WindowingApi.cs

@@ -1,5 +1,6 @@
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.CommonApi.Async;
+using PixiEditor.Extensions.CommonApi.Utilities;
 using PixiEditor.Extensions.CommonApi.Windowing;
 using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Extensions.WasmRuntime.Utilities;
@@ -13,7 +14,8 @@ internal class WindowingApi : ApiGroupHandler
     public int CreatePopupWindow(string title, Span<byte> bodySpan)
     {
         var body = LayoutBuilder.Deserialize(bodySpan, DuplicateResolutionTactic.ThrowException);
-        var popupWindow = Api.Windowing.CreatePopupWindow(title, body.BuildNative());
+        string localizedTitleKey = LocalizedString.FirstValidKey($"{Extension.Metadata.UniqueName}:{title}", title);
+        var popupWindow = Api.Windowing.CreatePopupWindow(localizedTitleKey, body.BuildNative());
 
         int handle = NativeObjectManager.AddObject(popupWindow);
         return handle;
@@ -37,8 +39,9 @@ internal class WindowingApi : ApiGroupHandler
     [ApiFunction("set_window_title")]
     public void SetWindowTitle(int handle, string title)
     {
+        string localizedTitleKey = LocalizedString.FirstValidKey($"{Extension.Metadata.UniqueName}:{title}", title);
         var window = NativeObjectManager.GetObject<PopupWindow>(handle);
-        window.Title = title;
+        window.Title = localizedTitleKey;
     }
 
     [ApiFunction("get_window_title")]

+ 11 - 0
src/PixiEditor.Extensions/Common/Localization/LocalizedString.cs

@@ -107,4 +107,15 @@ public struct LocalizedString
 
     public static implicit operator LocalizedString(string key) => new(key);
     public static implicit operator string(LocalizedString localizedString) => localizedString.Value;
+
+    public static string FirstValidKey(string key, string fallbackKey)
+    {
+        LocalizedString localizedString = new(key);
+        if (localizedString.Key == localizedString.Value)
+        {
+            return fallbackKey;
+        }
+
+        return key;
+    }
 }

+ 4 - 1
src/PixiEditor.Extensions/FlyUI/Converters/PathToBitmapConverter.cs

@@ -10,7 +10,10 @@ public class PathToBitmapConverter : IValueConverter
     {
         if (value is string path)
         {
-            return new Bitmap(path);
+            if (File.Exists(path))
+            {
+                return new Bitmap(path);
+            }
         }
         return null;
     }

+ 40 - 10
src/PixiEditor.Extensions/FlyUI/Elements/Column.cs

@@ -1,14 +1,31 @@
-using System.Collections.ObjectModel;
+using System.Collections.Immutable;
+using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using Avalonia.Controls;
 using Avalonia.Layout;
 using Avalonia.Threading;
+using PixiEditor.Extensions.UI.Panels;
 
 namespace PixiEditor.Extensions.FlyUI.Elements;
 
-public class Column : MultiChildLayoutElement
+public class Column : MultiChildLayoutElement, IPropertyDeserializable
 {
-    private StackPanel panel;
+    private MainAxisAlignment mainAxisAlignment;
+    private CrossAxisAlignment crossAxisAlignment;
+
+    private Panel panel;
+
+    public MainAxisAlignment MainAxisAlignment
+    {
+        get => mainAxisAlignment;
+        set => SetField(ref mainAxisAlignment, value);
+    }
+
+    public CrossAxisAlignment CrossAxisAlignment
+    {
+        get => crossAxisAlignment;
+        set => SetField(ref crossAxisAlignment, value);
+    }
 
     public Column()
     {
@@ -44,15 +61,28 @@ public class Column : MultiChildLayoutElement
 
     public override Control BuildNative()
     {
-        panel = new StackPanel()
-        {
-            Orientation = Orientation.Vertical,
-            HorizontalAlignment = HorizontalAlignment.Stretch,
-            VerticalAlignment = VerticalAlignment.Stretch
-        };
-        
+        panel = new ColumnPanel() { MainAxisAlignment = MainAxisAlignment, CrossAxisAlignment = CrossAxisAlignment };
+
         panel.Children.AddRange(Children.Select(x => x.BuildNative()));
 
         return panel;
     }
+
+    public IEnumerable<object> GetProperties()
+    {
+        yield return MainAxisAlignment;
+        yield return CrossAxisAlignment;
+    }
+
+    public void DeserializeProperties(ImmutableList<object> values)
+    {
+        if (values.Count < 2)
+            throw new ArgumentException("Invalid number of properties");
+
+        int mainAxisAlignment = (int)values[0];
+        int crossAxisAlignment = (int)values[1];
+
+        MainAxisAlignment = (MainAxisAlignment)mainAxisAlignment;
+        CrossAxisAlignment = (CrossAxisAlignment)crossAxisAlignment;
+    }
 }

+ 18 - 0
src/PixiEditor.Extensions/FlyUI/Elements/MainAxisAlignment.cs

@@ -0,0 +1,18 @@
+namespace PixiEditor.Extensions.FlyUI.Elements;
+
+public enum MainAxisAlignment
+{
+    Start,
+    Center,
+    End,
+    SpaceBetween,
+    SpaceAround,
+    SpaceEvenly
+}
+
+public enum CrossAxisAlignment
+{
+    Start,
+    Center,
+    End
+}

+ 43 - 7
src/PixiEditor.Extensions/FlyUI/Elements/Row.cs

@@ -1,13 +1,32 @@
-using System.Collections.Specialized;
+using System.Collections.Immutable;
+using System.Collections.Specialized;
 using Avalonia.Controls;
 using Avalonia.Layout;
 using Avalonia.Threading;
+using PixiEditor.Extensions.UI.Panels;
 
 namespace PixiEditor.Extensions.FlyUI.Elements;
 
-public class Row : MultiChildLayoutElement
+public class Row : MultiChildLayoutElement, IPropertyDeserializable
 {
-    private StackPanel panel;
+    private MainAxisAlignment mainAxisAlignment;
+    private CrossAxisAlignment crossAxisAlignment;
+
+    private Panel panel;
+
+    public MainAxisAlignment MainAxisAlignment
+    {
+        get => mainAxisAlignment;
+        set => SetField(ref mainAxisAlignment, value);
+    }
+
+    public CrossAxisAlignment CrossAxisAlignment
+    {
+        get => crossAxisAlignment;
+        set => SetField(ref crossAxisAlignment, value);
+    }
+
+
     public Row()
     {
     }
@@ -43,15 +62,32 @@ public class Row : MultiChildLayoutElement
 
     public override Control BuildNative()
     {
-        panel = new StackPanel()
+        panel = new RowPanel()
         {
-            Orientation = Orientation.Horizontal,
-            HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch,
-            VerticalAlignment = Avalonia.Layout.VerticalAlignment.Stretch
+            MainAxisAlignment = MainAxisAlignment,
+            CrossAxisAlignment = CrossAxisAlignment
         };
 
         panel.Children.AddRange(Children.Select(x => x.BuildNative()));
 
         return panel;
     }
+
+    public IEnumerable<object> GetProperties()
+    {
+        yield return MainAxisAlignment;
+        yield return CrossAxisAlignment;
+    }
+
+    public void DeserializeProperties(ImmutableList<object> values)
+    {
+        if (values.Count < 2)
+            throw new ArgumentException("Invalid number of properties");
+
+        int mainAxisAlignment = (int)values[0];
+        int crossAxisAlignment = (int)values[1];
+
+        MainAxisAlignment = (MainAxisAlignment)mainAxisAlignment;
+        CrossAxisAlignment = (CrossAxisAlignment)crossAxisAlignment;
+    }
 }

+ 105 - 0
src/PixiEditor.Extensions/UI/Panels/ColumnPanel.cs

@@ -0,0 +1,105 @@
+using Avalonia;
+using Avalonia.Controls;
+using PixiEditor.Extensions.FlyUI.Elements;
+
+namespace PixiEditor.Extensions.UI.Panels;
+
+public class ColumnPanel : Panel
+{
+    public MainAxisAlignment MainAxisAlignment { get; set; } = MainAxisAlignment.Start;
+    public CrossAxisAlignment CrossAxisAlignment { get; set; } = CrossAxisAlignment.Start;
+
+
+    protected override Size MeasureOverride(Size availableSize)
+    {
+        Size size = new(0, 0);
+        foreach (var child in Children)
+        {
+            child.Measure(availableSize);
+            size = new Size(Math.Max(size.Width, child.DesiredSize.Width), size.Height + child.DesiredSize.Height);
+        }
+
+        if (MainAxisAlignment == MainAxisAlignment.SpaceBetween)
+        {
+            size = new Size(size.Width, availableSize.Height);
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.SpaceAround)
+        {
+            size = new Size(size.Width, availableSize.Height);
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.SpaceEvenly)
+        {
+            size = new Size(size.Width, availableSize.Height);
+        }
+
+        if (CrossAxisAlignment == CrossAxisAlignment.Center)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+
+        if (CrossAxisAlignment == CrossAxisAlignment.End)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+
+        return size;
+    }
+
+    protected override Size ArrangeOverride(Size finalSize)
+    {
+        double totalYSpace = 0;
+
+        foreach (var child in Children)
+        {
+            totalYSpace += child.DesiredSize.Height;
+        }
+
+        bool stretchPlacement = MainAxisAlignment is MainAxisAlignment.SpaceBetween or MainAxisAlignment.SpaceAround
+            or MainAxisAlignment.SpaceEvenly;
+        double spaceBetween = 0;
+        double spaceBeforeAfter = 0;
+        if (stretchPlacement)
+        {
+            double freeSpace = finalSize.Height - totalYSpace;
+            spaceBetween = freeSpace / (Children.Count - 1);
+
+            if (MainAxisAlignment == MainAxisAlignment.SpaceAround)
+            {
+                spaceBetween = freeSpace / Children.Count;
+                spaceBeforeAfter = spaceBetween / 2f;
+            }
+            else if (MainAxisAlignment == MainAxisAlignment.SpaceEvenly)
+            {
+                spaceBeforeAfter = freeSpace / (Children.Count + 1);
+                spaceBetween = (freeSpace - spaceBeforeAfter) / Children.Count;
+            }
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.Center)
+        {
+            spaceBeforeAfter = (finalSize.Height - totalYSpace) / 2;
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.End)
+        {
+            spaceBeforeAfter = finalSize.Height - totalYSpace;
+        }
+
+        double yOffset = spaceBeforeAfter;
+        foreach (var child in Children)
+        {
+            double xOffset = 0;
+            if (CrossAxisAlignment == CrossAxisAlignment.Center)
+            {
+                xOffset = finalSize.Width / 2f - child.DesiredSize.Width / 2f;
+            }
+            else if (CrossAxisAlignment == CrossAxisAlignment.End)
+            {
+                xOffset = finalSize.Width - child.DesiredSize.Width;
+            }
+
+            child.Arrange(new Rect(xOffset, yOffset, child.DesiredSize.Width, child.DesiredSize.Height));
+            yOffset += child.DesiredSize.Height + spaceBetween;
+        }
+
+        return finalSize;
+    }
+}

+ 105 - 0
src/PixiEditor.Extensions/UI/Panels/RowPanel.cs

@@ -0,0 +1,105 @@
+using Avalonia;
+using Avalonia.Controls;
+using PixiEditor.Extensions.FlyUI.Elements;
+
+namespace PixiEditor.Extensions.UI.Panels;
+
+public class RowPanel : Panel
+{
+    public MainAxisAlignment MainAxisAlignment { get; set; } = MainAxisAlignment.Start;
+    public CrossAxisAlignment CrossAxisAlignment { get; set; } = CrossAxisAlignment.Start;
+
+
+    protected override Size MeasureOverride(Size availableSize)
+    {
+        Size size = new(0, 0);
+        foreach (var child in Children)
+        {
+            child.Measure(availableSize);
+            size = new Size(Math.Max(size.Width, child.DesiredSize.Width), size.Height + child.DesiredSize.Height);
+        }
+
+        if (MainAxisAlignment == MainAxisAlignment.SpaceBetween)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.SpaceAround)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.SpaceEvenly)
+        {
+            size = new Size (availableSize.Width, size.Height);
+        }
+
+        if (CrossAxisAlignment == CrossAxisAlignment.Center)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+
+        if (CrossAxisAlignment == CrossAxisAlignment.End)
+        {
+            size = new Size(availableSize.Width, size.Height);
+        }
+
+        return size;
+    }
+
+    protected override Size ArrangeOverride(Size finalSize)
+    {
+        double totalXSpace = 0;
+
+        foreach (var child in Children)
+        {
+            totalXSpace += child.DesiredSize.Width;
+        }
+
+        bool stretchPlacement = MainAxisAlignment is MainAxisAlignment.SpaceBetween or MainAxisAlignment.SpaceAround
+            or MainAxisAlignment.SpaceEvenly;
+        double spaceBetween = 0;
+        double spaceBeforeAfter = 0;
+        if (stretchPlacement)
+        {
+            double freeSpace = finalSize.Width - totalXSpace;
+            spaceBetween = freeSpace / (Children.Count - 1);
+
+            if (MainAxisAlignment == MainAxisAlignment.SpaceAround)
+            {
+                spaceBetween = freeSpace / Children.Count;
+                spaceBeforeAfter = spaceBetween / 2f;
+            }
+            else if (MainAxisAlignment == MainAxisAlignment.SpaceEvenly)
+            {
+                spaceBeforeAfter = freeSpace / (Children.Count + 1);
+                spaceBetween = (freeSpace - spaceBeforeAfter) / Children.Count;
+            }
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.Center)
+        {
+            spaceBeforeAfter = (finalSize.Width - totalXSpace) / 2;
+        }
+        else if (MainAxisAlignment == MainAxisAlignment.End)
+        {
+            spaceBeforeAfter = finalSize.Width - totalXSpace;
+        }
+
+        double xOffset = spaceBeforeAfter;
+        foreach (var child in Children)
+        {
+            double yOffset = 0;
+            if (CrossAxisAlignment == CrossAxisAlignment.Center)
+            {
+                yOffset = finalSize.Height / 2f - child.DesiredSize.Height / 2f;
+            }
+            else if (CrossAxisAlignment == CrossAxisAlignment.End)
+            {
+                yOffset = finalSize.Height - child.DesiredSize.Height;
+            }
+
+            child.Arrange(new Rect(xOffset, yOffset, child.DesiredSize.Width, child.DesiredSize.Height));
+            xOffset += child.DesiredSize.Width + spaceBetween;
+        }
+
+        return finalSize;
+    }
+}

+ 1 - 1
src/PixiEditor/Initialization/ClassicDesktopEntry.cs

@@ -115,7 +115,7 @@ internal class ClassicDesktopEntry
 
         ExtensionLoader extensionLoader = new ExtensionLoader(Paths.ExtensionPackagesPath, Paths.UserExtensionsPath);
         //TODO: fetch from extension store
-        extensionLoader.AddOfficialExtension("pixieditor.supporterpack",
+        extensionLoader.AddOfficialExtension("pixieditor.founderspack",
             new OfficialExtensionData("supporter-pack.snk", AdditionalContentProduct.SupporterPack));
         extensionLoader.AddOfficialExtension("pixieditor.beta", new OfficialExtensionData());
         if (!safeMode)

+ 2 - 2
src/PixiEditor/Models/ExtensionServices/CommandProvider.cs

@@ -49,9 +49,9 @@ public class CommandProvider : ICommandProvider
         CommandController.Current.AddManagedCommand(basicCommand);
     }
 
-    private static KeyCombination ToKeyCombination(Shortcut shortcut)
+    private static KeyCombination ToKeyCombination(Shortcut? shortcut)
     {
-        if (shortcut is { Key: 0, Modifiers: 0 })
+        if (shortcut is null or { Key: 0, Modifiers: 0 })
             return KeyCombination.None;
 
         return new KeyCombination((Key)shortcut.Key, (KeyModifiers)shortcut.Modifiers);

+ 1 - 1
src/PixiEditor/Models/ExtensionServices/WindowProvider.cs

@@ -41,7 +41,7 @@ public class WindowProvider : IWindowProvider
 
     public IPopupWindow CreatePopupWindow(string title, object body)
     {
-        return new PopupWindow(new PixiEditorPopup { Title = new LocalizedString(title), Content = body });
+        return new PopupWindow(new PixiEditorPopup { Title = title, Content = body });
     }
 
     public IPopupWindow GetWindow(BuiltInWindowType type)