Browse Source

Merge branch 'master' into autoupdate-linux

Krzysztof Krysiński 2 months ago
parent
commit
1c4cf88d88

+ 66 - 0
.github/workflows/tests-windows.yml

@@ -0,0 +1,66 @@
+name: Tests Windows
+
+on:
+  push:
+    branches: [ "master" ]
+  pull_request:
+    branches: [ "master" ]
+
+env:
+  wasiVer: 'wasi-sdk-25.0-x86_64-windows'
+  wasiUrl: 'https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-windows.tar.gz'
+
+jobs:
+
+  build:
+
+    strategy:
+      matrix:
+        configuration: [Release]
+
+    runs-on: windows-latest  # For a list of available runner types, refer to
+                             # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
+
+    steps:
+    - name: Checkout
+      uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+        submodules: 'recursive'
+
+    # Install the .NET Core workload
+    - name: Install .NET Core
+      uses: actions/setup-dotnet@v4
+      with:
+        dotnet-version: 8.0.x
+
+    - name: Install wasi-experimental workload
+      working-directory: tests
+      run: dotnet workload install wasi-experimental
+
+    - name: Download WASI SDK
+      run: |
+        Invoke-WebRequest -Uri "${{ env.wasiUrl }}" -OutFile "${{ env.wasiVer }}.tar.gz"
+
+    - name: Unpack WASI SDK
+      run: |
+              tar -xzf ${{ env.wasiVer }}.tar.gz
+              echo "Contents of directory after extraction:"
+              dir "${{ env.wasiVer }}"
+      shell: pwsh
+
+    - name: Set Environment Path for WASI SDK
+      run: |
+              $env:WASI_SDK_PATH = "${{ github.workspace }}\${{ env.wasiVer }}"
+              echo "WASI_SDK_PATH=$env:WASI_SDK_PATH" >> $env:GITHUB_ENV
+      shell: pwsh
+
+    - name: Verify Environment Path
+      run: |
+              Write-Host "Environment path set to: $env:WASI_SDK_PATH"
+      shell: pwsh
+
+    # Execute all unit tests in the solution
+    - name: Execute unit tests
+      working-directory: tests
+      run: dotnet test

+ 0 - 85
pipelines/Linux/tests-ubuntu.yml

@@ -1,85 +0,0 @@
-trigger:
-  - development
-  - master
-  - 2.0-cicd
-
-pool:
-  vmImage: 'ubuntu-latest'
-
-variables:
-  solution: '**/*.sln'
-  buildPlatform: 'linux-$(arch)'
-  buildConfiguration: 'Release'
-  wasiVer: 'wasi-sdk-24.0-$(wasi-arch)-linux'
-  wasiUrl: 'https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/$(wasiVer).tar.gz'
-
-steps:
-  - task: UseDotNet@2
-    displayName: 'Install .NET SDK'
-    inputs:
-      packageType: 'sdk'
-      version: '$(dotnetVersion)'
-  - task: CmdLine@2
-    displayName: 'Download WASI SDK'
-    inputs:
-      script: |
-        curl -L -o $(wasiVer).tar.gz $(wasiUrl)
-
-  - task: CmdLine@2
-    displayName: 'Unpack WASI SDK'
-    inputs:
-      script: |
-        tar -xzf $(wasiVer).tar.gz
-        echo "Contents of directory after extraction:"
-        dir $(wasiVer)
-
-  - task: PowerShell@2
-    displayName: 'Set Environment Path for WASI SDK'
-    inputs:
-      targetType: 'inline'
-      script: |
-        $env:WASI_SDK_PATH = "$(Get-Location)\$(wasiVer)"
-        Write-Host "##vso[task.setvariable variable=WASI_SDK_PATH]$env:WASI_SDK_PATH"
-
-  - task: PowerShell@2
-    displayName: 'Verify Environment Path'
-    inputs:
-      targetType: 'inline'
-      script: |
-        Write-Host "Environment path set to: $env:WASI_SDK_PATH"
-
-
-  - task: NuGetToolInstaller@1
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasi-wasm
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasi-experimental'
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasm-tools
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasm-tools'
-
-  - task: NuGetCommand@2
-    displayName: 'Restore solution'
-    inputs:
-      restoreSolution: '$(solution)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Build
-    inputs:
-      command: 'build'
-      projects: '**/*.csproj'
-      arguments: '--configuration Release -r $(buildPlatform)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Tests
-    inputs:
-      command: test
-      projects: '**/*Tests/*.csproj'
-      arguments: '--configuration $(buildConfiguration) -r $(buildPlatform)'

+ 0 - 85
pipelines/MacOS/tests-macos.yml

@@ -1,85 +0,0 @@
-trigger:
-  - development
-  - master
-  - 2.0-cicd
-
-pool:
-  vmImage: 'macos-latest'
-
-variables:
-  solution: '**/*.sln'
-  buildPlatform: 'osx-$(arch)'
-  buildConfiguration: 'Release'
-  wasiVer: 'wasi-sdk-24.0-$(wasi-arch)-macos'
-  wasiUrl: 'https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/$(wasiVer).tar.gz'
-
-steps:
-  - task: UseDotNet@2
-    displayName: 'Install .NET SDK'
-    inputs:
-      packageType: 'sdk'
-      version: '$(dotnetVersion)'
-  - task: CmdLine@2
-    displayName: 'Download WASI SDK'
-    inputs:
-      script: |
-        curl -L -o $(wasiVer).tar.gz $(wasiUrl)
-
-  - task: CmdLine@2
-    displayName: 'Unpack WASI SDK'
-    inputs:
-      script: |
-        tar -xzf $(wasiVer).tar.gz
-        echo "Contents of directory after extraction:"
-        dir $(wasiVer)
-
-  - task: PowerShell@2
-    displayName: 'Set Environment Path for WASI SDK'
-    inputs:
-      targetType: 'inline'
-      script: |
-        $env:WASI_SDK_PATH = "$(Get-Location)\$(wasiVer)"
-        Write-Host "##vso[task.setvariable variable=WASI_SDK_PATH]$env:WASI_SDK_PATH"
-
-  - task: PowerShell@2
-    displayName: 'Verify Environment Path'
-    inputs:
-      targetType: 'inline'
-      script: |
-        Write-Host "Environment path set to: $env:WASI_SDK_PATH"
-
-
-  - task: NuGetToolInstaller@1
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasi-wasm
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasi-experimental'
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasm-tools
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasm-tools'
-
-  - task: NuGetCommand@2
-    displayName: 'Restore solution'
-    inputs:
-      restoreSolution: '$(solution)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Build
-    inputs:
-      command: 'build'
-      projects: '**/*.csproj'
-      arguments: '--configuration Release -r $(buildPlatform)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Tests
-    inputs:
-      command: test
-      projects: '**/*Tests/*.csproj'
-      arguments: '--configuration $(buildConfiguration) -r $(buildPlatform)'

+ 0 - 85
pipelines/Windows/tests-windows.yml

@@ -1,85 +0,0 @@
-trigger:
-  - development
-  - master
-  - 2.0-cicd
-
-pool:
-  vmImage: 'windows-latest'
-
-variables:
-  solution: '**/*.sln'
-  buildPlatform: 'win-$(arch)'
-  buildConfiguration: 'Release'
-  wasiVer: 'wasi-sdk-24.0-$(wasi-arch)-windows'
-  wasiUrl: 'https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/$(wasiVer).tar.gz'
-
-steps:
-  - task: UseDotNet@2
-    displayName: 'Install .NET SDK'
-    inputs:
-      packageType: 'sdk'
-      version: '$(dotnetVersion)'
-
-  - task: CmdLine@2
-    displayName: 'Download WASI SDK'
-    inputs:
-      script: |
-        curl -L -o $(wasiVer).tar.gz $(wasiUrl)
-
-  - task: CmdLine@2
-    displayName: 'Unpack WASI SDK'
-    inputs:
-      script: |
-        tar -xzf $(wasiVer).tar.gz
-        echo "Contents of directory after extraction:"
-        dir $(wasiVer)
-
-  - task: PowerShell@2
-    displayName: 'Set Environment Path for WASI SDK'
-    inputs:
-      targetType: 'inline'
-      script: |
-        $env:WASI_SDK_PATH = "$(Get-Location)\$(wasiVer)"
-        Write-Host "##vso[task.setvariable variable=WASI_SDK_PATH]$env:WASI_SDK_PATH"
-
-  - task: PowerShell@2
-    displayName: 'Verify Environment Path'
-    inputs:
-      targetType: 'inline'
-      script: |
-        Write-Host "Environment path set to: $env:WASI_SDK_PATH"
-
-  - task: NuGetToolInstaller@1
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasi-wasm
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasi-experimental'
-
-  - task: DotNetCoreCLI@2
-    displayName: Install wasm-tools
-    inputs:
-      command: 'custom'
-      custom: 'workload'
-      arguments: 'install wasm-tools'
-
-  - task: NuGetCommand@2
-    displayName: 'Restore solution'
-    inputs:
-      restoreSolution: '$(solution)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Build
-    inputs:
-      command: 'build'
-      projects: '**/*.csproj'
-      arguments: '--configuration Release -r $(buildPlatform)'
-
-  - task: DotNetCoreCLI@2
-    displayName: Tests
-    inputs:
-      command: test
-      projects: '**/*Tests/*.csproj'
-      arguments: '--configuration $(buildConfiguration) -r $(buildPlatform)'

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -164,10 +164,11 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
         IReadOnlyDictionary<string, object> data, List<IChangeInfo> infos)
     {
         base.DeserializeAdditionalData(target, data, infos);
-        EmbeddedShapeData = (ShapeVectorData)data["ShapeData"];
+        EmbeddedShapeData = data["ShapeData"] as ShapeVectorData;
 
         if (EmbeddedShapeData == null)
         {
+            Console.WriteLine("Failed to deserialize shape data");
             return;
         }
 

+ 3 - 1
src/PixiEditor.Extensions.CommonApi/Utilities/ByteWriter.cs

@@ -1,3 +1,5 @@
+using System.Text;
+
 namespace PixiEditor.Extensions.CommonApi.Utilities;
 
 public class ByteWriter
@@ -19,8 +21,8 @@ public class ByteWriter
 
     public void WriteString(string value)
     {
+        WriteInt(Encoding.UTF8.GetByteCount(value));
         byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(value);
-        WriteInt(stringBytes.Length);
         _buffer.AddRange(stringBytes);
     }
 

+ 17 - 8
src/PixiEditor/Models/Serialization/Factories/ByteExtractor.cs

@@ -86,14 +86,10 @@ public class ByteExtractor
     public string GetString()
     {
         int length = GetInt();
-        StringBuilder builder = new StringBuilder();
-        
-        for (int i = 0; i < length; i++)
-        {
-            builder.Append((char)GetInt());
-        }
-        
-        return builder.ToString();
+        string value = Encoding.UTF8.GetString(_data, Position, length);
+
+        Position += length;
+        return value;
     }
 
     public float GetFloat()
@@ -113,4 +109,17 @@ public class ByteExtractor
         
         return value;
     }
+
+    internal string GetStringLegacyDontUse()
+    {
+        int length = GetInt();
+
+        StringBuilder sb = new StringBuilder(length);
+        for (int i = 0; i < length; i++)
+        {
+            sb.Append((char)GetInt());
+        }
+
+        return sb.ToString();
+    }
 }

+ 3 - 1
src/PixiEditor/Models/Serialization/Factories/FontFamilySerializationFactory.cs

@@ -36,7 +36,9 @@ public class FontFamilySerializationFactory : SerializationFactory<byte[], FontF
         }
 
         ByteExtractor extractor = new ByteExtractor(bytes);
-        string fontFamily = extractor.GetString();
+
+        string fontFamily = DeserializeStringCompatible(extractor, serializerData);
+
         bool isFontFromFile = extractor.GetBool();
         string fontPath = null;
         if (isFontFromFile && ResourceLocator != null)

+ 17 - 0
src/PixiEditor/Models/Serialization/Factories/SerializationFactory.cs

@@ -65,6 +65,23 @@ public abstract class SerializationFactory<TSerializable, TOriginal> : Serializa
     {
         return TryDeserialize(rawData, out TOriginal original, serializerData) ? original : default;
     }
+
+    protected string DeserializeStringCompatible(
+        ByteExtractor extractor,
+        (string serializerName, string serializerVersion) serializerData)
+    {
+        if (serializerData.serializerName != "PixiEditor")
+        {
+            return extractor.GetString();
+        }
+
+        if (IsFilePreVersion(serializerData, new Version(2, 0, 0, 87)))
+        {
+            return extractor.GetStringLegacyDontUse();
+        }
+
+        return extractor.GetString();
+    }
     
     public override Type OriginalType => typeof(TOriginal);
 }

+ 4 - 3
src/PixiEditor/Models/Serialization/Factories/TextSerializationFactory.cs

@@ -46,10 +46,11 @@ internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVe
         float strokeWidth, (string serializerName, string serializerVersion) serializerData,
         out TextVectorData original)
     {
-        string text = extractor.GetString();
+        string text = DeserializeStringCompatible(extractor, serializerData);
+
         VecD position = extractor.GetVecD();
         bool antiAlias = extractor.GetBool();
-        string fontFamily = extractor.GetString();
+        string fontFamily = DeserializeStringCompatible(extractor, serializerData);
         bool isFontFromFile = extractor.GetBool();
         string fontPath = null;
         if (isFontFromFile && ResourceLocator != null)
@@ -67,7 +68,7 @@ internal class TextSerializationFactory : VectorShapeSerializationFactory<TextVe
         VectorPath path = null;
         if (hasPath)
         {
-            path = VectorPath.FromSvgPath(extractor.GetString());
+            path = VectorPath.FromSvgPath(DeserializeStringCompatible(extractor, serializerData));
         }
 
         FontFamilyName family =

+ 1 - 1
src/PixiEditor/Models/Serialization/Factories/VectorPathSerializationFactory.cs

@@ -51,7 +51,7 @@ internal class VectorPathSerializationFactory : VectorShapeSerializationFactory<
         VectorPath path;
         if (IsOldSerializer(serializerData))
         {
-            string svgPath = extractor.GetString();
+            string svgPath = extractor.GetStringLegacyDontUse();
             path = VectorPath.FromSvgPath(svgPath);
         }
         else

+ 8 - 5
src/PixiEditor/Models/Serialization/Factories/VectorShapeSerializationFactory.cs

@@ -20,7 +20,8 @@ public abstract class VectorShapeSerializationFactory<T> : SerializationFactory<
 
         foreach (Type type in types)
         {
-            if (type.IsAssignableTo(typeof(IPaintableSerializationFactory)) && type is { IsAbstract: false, IsInterface: false })
+            if (type.IsAssignableTo(typeof(IPaintableSerializationFactory)) &&
+                type is { IsAbstract: false, IsInterface: false })
             {
                 factories.Add((SerializationFactory)Activator.CreateInstance(type));
             }
@@ -61,9 +62,9 @@ public abstract class VectorShapeSerializationFactory<T> : SerializationFactory<
         ByteExtractor extractor = new ByteExtractor(data);
 
         Matrix3X3 matrix = extractor.GetMatrix3X3();
-        Paintable strokeColor = TryGetPaintable(extractor, fileIsPrePaintables);
+        Paintable strokeColor = TryGetPaintable(extractor, fileIsPrePaintables, serializerData);
         bool fill = TryGetBool(extractor, serializerData);
-        Paintable fillColor = TryGetPaintable(extractor, fileIsPrePaintables);
+        Paintable fillColor = TryGetPaintable(extractor, fileIsPrePaintables, serializerData);
         float strokeWidth;
         // Previous versions of the serializer saved stroke as int, and serializer data didn't exist
         if (string.IsNullOrEmpty(serializerData.serializerVersion) &&
@@ -100,14 +101,16 @@ public abstract class VectorShapeSerializationFactory<T> : SerializationFactory<
         return extractor.GetBool();
     }
 
-    private Paintable TryGetPaintable(ByteExtractor extractor, bool fileIsPrePaintables)
+    private Paintable TryGetPaintable(ByteExtractor extractor, bool fileIsPrePaintables,
+        (string serializerName, string serializerVersion) serializerData)
     {
         if (fileIsPrePaintables)
         {
             return new ColorPaintable(extractor.GetColor());
         }
 
-        string paintableType = extractor.GetString();
+        string paintableType = DeserializeStringCompatible(extractor, serializerData);
+
         SerializationFactory factory = PaintableFactories.FirstOrDefault(f => f.DeserializationId == paintableType);
         if (factory == null)
         {

+ 2 - 2
src/PixiEditor/Properties/AssemblyInfo.cs

@@ -43,5 +43,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.0.0.88")]
-[assembly: AssemblyFileVersion("2.0.0.88")]
+[assembly: AssemblyVersion("2.0.0.89")]
+[assembly: AssemblyFileVersion("2.0.0.89")]

+ 1 - 1
src/PixiEditor/ViewModels/Menu/MenuBarViewModel.cs

@@ -66,7 +66,7 @@ internal class MenuBarViewModel : PixiObservableObject
     {
         menuItemBuilders = serviceProvider.GetServices<MenuItemBuilder>().ToArray();
         commandController = controller;
-        BuildMenu(controller);
+        RebuildMenu();
         controller.Commands.CommandAdded += CommandsOnCommandAdded;
     }
 

+ 9 - 0
src/PixiEditor/ViewModels/SubViewModels/FileViewModel.cs

@@ -685,6 +685,15 @@ internal class FileViewModel : SubViewModel<ViewModelMain>
         var history =
             preferences.GetLocalPreference<List<AutosaveHistorySession>>(PreferencesConstants.AutosaveHistory);
 
+        bool autosaveEnabled = preferences.GetPreference<bool>(
+            PreferencesConstants.AutosaveEnabled,
+            PreferencesConstants.AutosaveEnabledDefault);
+
+        if(!autosaveEnabled)
+        {
+            return;
+        }
+
         // There are no autosave attempts .. but what if the user has just launched pixieditor for the first time,
         // and it unexpectedly closed before auto saving anything. They could've still had some files open, and they won't be reopened in this session
         // I'll say this is by design

+ 1 - 0
tests/PixiEditor.Tests/PixiEditor.Tests.csproj

@@ -31,6 +31,7 @@
       <ProjectReference Include="..\..\src\PixiEditor.Desktop\PixiEditor.Desktop.csproj" />
       <ProjectReference Include="..\..\src\PixiEditor.Linux\PixiEditor.Linux.csproj" />
       <ProjectReference Include="..\..\src\PixiEditor.MacOs\PixiEditor.MacOs.csproj" />
+        <ProjectReference Include="..\..\src\PixiEditor.Windows\PixiEditor.Windows.csproj" />
     </ItemGroup>
     
     <ItemGroup>

+ 0 - 2
tests/PixiEditor.Tests/PixiEditorTest.cs

@@ -1,7 +1,5 @@
 using Drawie.Backend.Core.Bridge;
 using Drawie.Numerics;
-using Drawie.RenderApi.Vulkan;
-using Drawie.Silk;
 using Drawie.Skia;
 using Drawie.Windowing;
 using DrawiEngine;

+ 19 - 0
tests/PixiEditor.Tests/SerializationTests.cs

@@ -1,3 +1,4 @@
+using Avalonia.Headless.XUnit;
 using Drawie.Backend.Core.Bridge;
 using Drawie.Backend.Core.ColorsImpl.Paintables;
 using Drawie.Backend.Core.Surfaces.ImageData;
@@ -5,6 +6,7 @@ using Drawie.Skia;
 using DrawiEngine;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Changes.NodeGraph;
+using PixiEditor.Models.IO;
 using PixiEditor.Models.Serialization;
 using PixiEditor.Models.Serialization.Factories;
 using PixiEditor.Models.Serialization.Factories.Paintables;
@@ -47,4 +49,21 @@ public class SerializationTests : PixiEditorTest
             Assert.NotNull(factory);
         }
     }
+
+    [AvaloniaTheory]
+    [InlineData("Fibi")]
+    [InlineData("Pond")]
+    [InlineData("SmlPxlCircShadWithMask")]
+    [InlineData("SmallPixelArtCircleShadow")]
+    [InlineData("SmlPxlCircShadWithMaskClipped")]
+    [InlineData("SmlPxlCircShadWithMaskClippedInFolder")]
+    [InlineData("VectorRectangleClippedToCircle")]
+    [InlineData("VectorRectangleClippedToCircleShadowFilter")]
+    [InlineData("VectorRectangleClippedToCircleMasked")]
+    public void TestThatDeserializationOfSampleFilesDoesntThrow(string fileName)
+    {
+        string pixiFile = Path.Combine("TestFiles", "RenderTests", fileName + ".pixi");
+        var document = Importer.ImportDocument(pixiFile);
+        Assert.NotNull(document);
+    }
 }

+ 7 - 7
tests/PixiEditorTests.sln

@@ -67,8 +67,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.AnimationRendere
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.UI.Common", "..\src\PixiEditor.UI.Common\PixiEditor.UI.Common.csproj", "{13484484-682F-4D7A-AEF2-ECAF3A601311}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.Windows", "..\src\PixiEditor.Windows\PixiEditor.Windows.csproj", "{D5A9B447-642A-4655-A8BE-CC59AD6BE275}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.Platform", "..\src\PixiEditor.Platform\PixiEditor.Platform.csproj", "{61696194-C130-4388-9607-DA2D5295DC1F}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiParser", "..\src\PixiParser\src\PixiParser\PixiParser.csproj", "{2AFF4096-A539-4A01-B4F4-60389C11C039}"
@@ -125,6 +123,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drawie.Windowing", "..\src\
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drawie.Windowing.Glfw", "..\src\Drawie\src\Drawie.Windowing.Glfw\Drawie.Windowing.Glfw.csproj", "{B13E1D5E-EF6B-4193-8BE6-4C85F8C1EE59}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.Windows", "..\src\PixiEditor.Windows\PixiEditor.Windows.csproj", "{2D1F681A-9C3F-4253-954E-E5A24285AD5D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -242,10 +242,6 @@ Global
 		{13484484-682F-4D7A-AEF2-ECAF3A601311}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{13484484-682F-4D7A-AEF2-ECAF3A601311}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{13484484-682F-4D7A-AEF2-ECAF3A601311}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D5A9B447-642A-4655-A8BE-CC59AD6BE275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D5A9B447-642A-4655-A8BE-CC59AD6BE275}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D5A9B447-642A-4655-A8BE-CC59AD6BE275}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D5A9B447-642A-4655-A8BE-CC59AD6BE275}.Release|Any CPU.Build.0 = Release|Any CPU
 		{61696194-C130-4388-9607-DA2D5295DC1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{61696194-C130-4388-9607-DA2D5295DC1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{61696194-C130-4388-9607-DA2D5295DC1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -358,6 +354,10 @@ Global
 		{B13E1D5E-EF6B-4193-8BE6-4C85F8C1EE59}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B13E1D5E-EF6B-4193-8BE6-4C85F8C1EE59}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B13E1D5E-EF6B-4193-8BE6-4C85F8C1EE59}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2D1F681A-9C3F-4253-954E-E5A24285AD5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2D1F681A-9C3F-4253-954E-E5A24285AD5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2D1F681A-9C3F-4253-954E-E5A24285AD5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2D1F681A-9C3F-4253-954E-E5A24285AD5D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{0EF3CAB9-7361-472C-8789-D17D4EA2DEBB} = {D914C08C-5F1A-4E13-AAA6-F25E8C9748E2}
@@ -389,7 +389,6 @@ Global
 		{6245051F-835D-41EB-89E0-95652B51153C} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{2A54A13E-6D54-4BC6-836D-740F12B62D02} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{13484484-682F-4D7A-AEF2-ECAF3A601311} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
-		{D5A9B447-642A-4655-A8BE-CC59AD6BE275} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{61696194-C130-4388-9607-DA2D5295DC1F} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{2AFF4096-A539-4A01-B4F4-60389C11C039} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{7E65B1D3-507E-4C89-92A9-D25D0097888B} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
@@ -418,5 +417,6 @@ Global
 		{F021BE50-BDFB-427C-9495-888347C4E3B3} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{37662F23-90F7-4B41-8E45-5D1B09A96803} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 		{B13E1D5E-EF6B-4193-8BE6-4C85F8C1EE59} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
+		{2D1F681A-9C3F-4253-954E-E5A24285AD5D} = {E118E6FE-67E7-4472-A8D7-E7F470E66131}
 	EndGlobalSection
 EndGlobal