summaryrefslogtreecommitdiff
path: root/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization
diff options
context:
space:
mode:
authorchai <215380520@qq.com>2024-06-03 10:15:45 +0800
committerchai <215380520@qq.com>2024-06-03 10:15:45 +0800
commitacea7b2e728787a0d83bbf83c8c1f042d2c32e7e (patch)
tree0bfec05c1ca2d71be2c337bcd110a0421f19318b /Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization
parent88febcb02bf127d961c6471d9e846c0e1315f5c3 (diff)
+ plugins project
Diffstat (limited to 'Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization')
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlJsonConverter.cs67
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlStyleJsonConverter.cs89
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiJsonSerializerOptionsProvider.cs38
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiNinePatchRegion2DJsonConverter.cs15
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureAtlasJsonConverter.cs31
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureRegionService.cs16
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/HorizontalAlignmentConverter.cs32
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/SkinJsonConverter.cs57
-rw-r--r--Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/VerticalAlignmentConverter.cs32
9 files changed, 377 insertions, 0 deletions
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlJsonConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlJsonConverter.cs
new file mode 100644
index 0000000..a9c71f8
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlJsonConverter.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using MonoGame.Extended.Gui.Controls;
+
+namespace MonoGame.Extended.Gui.Serialization
+{
+ public class ControlJsonConverter : JsonConverter<Control>
+ {
+ private readonly IGuiSkinService _guiSkinService;
+ private readonly ControlStyleJsonConverter _styleConverter;
+ private const string _styleProperty = "Style";
+
+ public ControlJsonConverter(IGuiSkinService guiSkinService, params Type[] customControlTypes)
+ {
+ _guiSkinService = guiSkinService;
+ _styleConverter = new ControlStyleJsonConverter(customControlTypes);
+ }
+
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Control);
+
+ /// <inheritdoc />
+ public override Control Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var style = _styleConverter.Read(ref reader, typeToConvert, options);
+ var template = GetControlTemplate(style);
+ var skin = _guiSkinService.Skin;
+ var control = skin.Create(style.TargetType, template);
+
+ var itemsControl = control as ItemsControl;
+ if (itemsControl != null)
+ {
+ object childControls;
+
+ if (style.TryGetValue(nameof(ItemsControl.Items), out childControls))
+ {
+ var controlCollection = childControls as ControlCollection;
+
+ if (controlCollection != null)
+ {
+ foreach (var child in controlCollection)
+ itemsControl.Items.Add(child);
+ }
+ }
+ }
+
+ style.Apply(control);
+ return control;
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, Control value, JsonSerializerOptions options) { }
+
+
+
+ private static string GetControlTemplate(ControlStyle style)
+ {
+ object template;
+
+ if (style.TryGetValue(_styleProperty, out template))
+ return template as string;
+
+ return null;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlStyleJsonConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlStyleJsonConverter.cs
new file mode 100644
index 0000000..c31549b
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/ControlStyleJsonConverter.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using MonoGame.Extended.Collections;
+using MonoGame.Extended.Gui.Controls;
+
+namespace MonoGame.Extended.Gui.Serialization
+{
+ public class ControlStyleJsonConverter : JsonConverter<ControlStyle>
+ {
+ private readonly Dictionary<string, Type> _controlTypes;
+ private const string _typeProperty = "Type";
+ private const string _nameProperty = "Name";
+
+ public ControlStyleJsonConverter(params Type[] customControlTypes)
+ {
+ _controlTypes = typeof(Control)
+ .GetTypeInfo()
+ .Assembly
+ .ExportedTypes
+ .Concat(customControlTypes)
+ .Where(t => t.GetTypeInfo().IsSubclassOf(typeof(Control)))
+ .ToDictionary(t => t.Name);
+ }
+
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(ControlStyle);
+
+ /// <inheritdoc />
+ public override ControlStyle Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var dictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);
+ var name = dictionary.GetValueOrDefault(_nameProperty) as string;
+ var typeName = dictionary.GetValueOrDefault(_typeProperty) as string;
+
+ if (!_controlTypes.TryGetValue(typeName, out Type controlType))
+ throw new FormatException("invalid control type: " + typeName);
+
+ var targetType = typeName != null ? controlType : typeof(Control);
+ var properties = targetType
+ .GetRuntimeProperties()
+ .ToDictionary(p => p.Name);
+ var style = new ControlStyle(name, targetType);
+
+ foreach (var keyValuePair in dictionary.Where(i => i.Key != _typeProperty))
+ {
+ var propertyName = keyValuePair.Key;
+ var rawValue = keyValuePair.Value;
+
+ PropertyInfo propertyInfo;
+ var value = properties.TryGetValue(propertyName, out propertyInfo)
+ ? DeserializeValueAs(rawValue, propertyInfo.PropertyType)
+ : DeserializeValueAs(rawValue, typeof(object));
+
+ style.Add(propertyName, value);
+ }
+
+ return style;
+ }
+
+ private static object DeserializeValueAs(object value, Type type)
+ {
+ var json = JsonSerializer.Serialize(value, type);
+ return JsonSerializer.Deserialize(json, type);
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, ControlStyle value, JsonSerializerOptions options)
+ {
+ var style = (ControlStyle)value;
+ var dictionary = new Dictionary<string, object> { [_typeProperty] = style.TargetType.Name };
+
+ foreach (var keyValuePair in style)
+ dictionary.Add(keyValuePair.Key, keyValuePair.Value);
+
+ JsonSerializer.Serialize(writer, dictionary);
+ }
+
+
+
+
+
+
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiJsonSerializerOptionsProvider.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiJsonSerializerOptionsProvider.cs
new file mode 100644
index 0000000..5ebc880
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiJsonSerializerOptionsProvider.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.Xna.Framework.Content;
+using MonoGame.Extended.BitmapFonts;
+using MonoGame.Extended.Serialization;
+
+namespace MonoGame.Extended.Gui.Serialization;
+
+public static class GuiJsonSerializerOptionsProvider
+{
+ public static JsonSerializerOptions GetOptions(ContentManager contentManager, params Type[] customControlTypes)
+ {
+ var options = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ };
+
+ var textureRegionService = new GuiTextureRegionService();
+
+ options.Converters.Add(new Vector2JsonConverter());
+ options.Converters.Add(new SizeJsonConverter());
+ options.Converters.Add(new Size2JsonConverter());
+ options.Converters.Add(new ColorJsonConverter());
+ options.Converters.Add(new ThicknessJsonConverter());
+ options.Converters.Add(new ContentManagerJsonConverter<BitmapFont>(contentManager, font => font.Name));
+ options.Converters.Add(new ControlStyleJsonConverter(customControlTypes));
+ options.Converters.Add(new GuiTextureAtlasJsonConverter(contentManager, textureRegionService));
+ options.Converters.Add(new GuiNinePatchRegion2DJsonConverter(textureRegionService));
+ options.Converters.Add(new TextureRegion2DJsonConverter(textureRegionService));
+ options.Converters.Add(new VerticalAlignmentConverter());
+ options.Converters.Add(new HorizontalAlignmentConverter());
+
+ return options;
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiNinePatchRegion2DJsonConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiNinePatchRegion2DJsonConverter.cs
new file mode 100644
index 0000000..9be58e5
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiNinePatchRegion2DJsonConverter.cs
@@ -0,0 +1,15 @@
+using MonoGame.Extended.Serialization;
+
+namespace MonoGame.Extended.Gui.Serialization
+{
+ public class GuiNinePatchRegion2DJsonConverter : NinePatchRegion2DJsonConverter
+ {
+ private readonly IGuiTextureRegionService _textureRegionService;
+
+ public GuiNinePatchRegion2DJsonConverter(IGuiTextureRegionService textureRegionService)
+ : base(textureRegionService)
+ {
+ _textureRegionService = textureRegionService;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureAtlasJsonConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureAtlasJsonConverter.cs
new file mode 100644
index 0000000..a0617cf
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureAtlasJsonConverter.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Text.Json;
+using Microsoft.Xna.Framework.Content;
+using MonoGame.Extended.Serialization;
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Gui.Serialization
+{
+ public class GuiTextureAtlasJsonConverter : ContentManagerJsonConverter<TextureAtlas>
+ {
+ private readonly IGuiTextureRegionService _textureRegionService;
+
+ public GuiTextureAtlasJsonConverter(ContentManager contentManager, IGuiTextureRegionService textureRegionService)
+ : base(contentManager, atlas => atlas.Name)
+ {
+ _textureRegionService = textureRegionService;
+ }
+
+ /// <inheritdoc />
+ public override TextureAtlas Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var textureAtlas = base.Read(ref reader, typeToConvert, options);
+ if (textureAtlas is not null)
+ {
+ _textureRegionService.TextureAtlases.Add(textureAtlas);
+ }
+
+ return textureAtlas;
+ }
+ }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureRegionService.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureRegionService.cs
new file mode 100644
index 0000000..cf9ab9e
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/GuiTextureRegionService.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using MonoGame.Extended.Serialization;
+using MonoGame.Extended.TextureAtlases;
+
+namespace MonoGame.Extended.Gui.Serialization
+{
+ public interface IGuiTextureRegionService : ITextureRegionService
+ {
+ IList<TextureAtlas> TextureAtlases { get; }
+ IList<NinePatchRegion2D> NinePatches { get; }
+ }
+
+ public class GuiTextureRegionService : TextureRegionService, IGuiTextureRegionService
+ {
+ }
+} \ No newline at end of file
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/HorizontalAlignmentConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/HorizontalAlignmentConverter.cs
new file mode 100644
index 0000000..a696528
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/HorizontalAlignmentConverter.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MonoGame.Extended.Gui.Serialization;
+
+public class HorizontalAlignmentConverter : JsonConverter<HorizontalAlignment>
+{
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(HorizontalAlignment);
+
+ /// <inheritdoc />
+ public override HorizontalAlignment Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var value = reader.GetString();
+
+ if (value.Equals("Center", StringComparison.OrdinalIgnoreCase) || value.Equals("Centre", StringComparison.OrdinalIgnoreCase))
+ {
+ return HorizontalAlignment.Centre;
+ }
+
+ if (Enum.TryParse<HorizontalAlignment>(value, true, out var alignment))
+ {
+ return alignment;
+ }
+
+ throw new InvalidOperationException($"Invalid value for '{nameof(HorizontalAlignment)}'");
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, HorizontalAlignment value, JsonSerializerOptions options) { }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/SkinJsonConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/SkinJsonConverter.cs
new file mode 100644
index 0000000..016ea6d
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/SkinJsonConverter.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+
+namespace MonoGame.Extended.Gui.Serialization;
+
+public interface IGuiSkinService
+{
+ Skin Skin { get; set; }
+}
+
+public class SkinService : IGuiSkinService
+{
+ public Skin Skin { get; set; }
+}
+
+public class SkinJsonConverter : JsonConverter<Skin>
+{
+ private readonly ContentManager _contentManager;
+ private readonly IGuiSkinService _skinService;
+ private readonly Type[] _customControlTypes;
+
+ public SkinJsonConverter(ContentManager contentManager, IGuiSkinService skinService, params Type[] customControlTypes)
+ {
+ _contentManager = contentManager;
+ _skinService = skinService;
+ _customControlTypes = customControlTypes;
+ }
+
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(Skin);
+
+ /// <inheritdoc />
+ public override Skin Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ var assetName = reader.GetString();
+
+ // TODO: Load this using the ContentManager instead.
+ using (var stream = TitleContainer.OpenStream(assetName))
+ {
+ var skin = Skin.FromStream(_contentManager, stream, _customControlTypes);
+ _skinService.Skin = skin;
+ return skin;
+ }
+
+ }
+
+ throw new InvalidOperationException($"{nameof(SkinJsonConverter)} can only convert from a string");
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, Skin value, JsonSerializerOptions options) { }
+}
diff --git a/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/VerticalAlignmentConverter.cs b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/VerticalAlignmentConverter.cs
new file mode 100644
index 0000000..bc55cda
--- /dev/null
+++ b/Plugins/MonoGame.Extended/source/MonoGame.Extended.Gui/Serialization/VerticalAlignmentConverter.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace MonoGame.Extended.Gui.Serialization;
+
+public class VerticalAlignmentConverter : JsonConverter<VerticalAlignment>
+{
+ /// <inheritdoc />
+ public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(VerticalAlignment);
+
+ /// <inheritdoc />
+ public override VerticalAlignment Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ var value = reader.GetString();
+
+ if (value.Equals("Center", StringComparison.OrdinalIgnoreCase) || value.Equals("Centre", StringComparison.OrdinalIgnoreCase))
+ {
+ return VerticalAlignment.Centre;
+ }
+
+ if (Enum.TryParse<VerticalAlignment>(value, true, out var alignment))
+ {
+ return alignment;
+ }
+
+ throw new InvalidOperationException($"Invalid value for '{nameof(VerticalAlignment)}'");
+ }
+
+ /// <inheritdoc />
+ public override void Write(Utf8JsonWriter writer, VerticalAlignment value, JsonSerializerOptions options) { }
+}