diff --git a/Source/Engine/Serialization/JsonConverters.cs b/Source/Engine/Serialization/JsonConverters.cs
index 04a20fdb4..f225c29d8 100644
--- a/Source/Engine/Serialization/JsonConverters.cs
+++ b/Source/Engine/Serialization/JsonConverters.cs
@@ -442,7 +442,7 @@ namespace FlaxEngine.Json
///
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
- var result = Activator.CreateInstance(objectType);
+ var result = existingValue ?? Activator.CreateInstance(objectType);
if (reader.TokenType == JsonToken.String)
{
JsonSerializer.ParseID((string)reader.Value, out var id);
@@ -483,6 +483,34 @@ namespace FlaxEngine.Json
}
}
+ internal class ControlReferenceConverter : JsonConverter
+ {
+ ///
+ public override unsafe void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var id = (value as IControlReference)?.UIControl?.ID ?? Guid.Empty;
+ writer.WriteValue(JsonSerializer.GetStringID(&id));
+ }
+
+ ///
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
+ {
+ var result = existingValue ?? Activator.CreateInstance(objectType);
+ if (reader.TokenType == JsonToken.String && result is IControlReference controlReference)
+ {
+ JsonSerializer.ParseID((string)reader.Value, out var id);
+ controlReference.UIControl = Object.Find(ref id);
+ }
+ return result;
+ }
+
+ ///
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType.Name.StartsWith("ControlReference", StringComparison.Ordinal);
+ }
+ }
+
/*
///
/// Serialize Guid values using `N` format
diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs
index f13be1e8f..59b13c549 100644
--- a/Source/Engine/Serialization/JsonSerializer.cs
+++ b/Source/Engine/Serialization/JsonSerializer.cs
@@ -194,6 +194,7 @@ namespace FlaxEngine.Json
settings.Converters.Add(new SoftObjectReferenceConverter());
settings.Converters.Add(new SoftTypeReferenceConverter());
settings.Converters.Add(new BehaviorKnowledgeSelectorAnyConverter());
+ settings.Converters.Add(new ControlReferenceConverter());
settings.Converters.Add(new MarginConverter());
settings.Converters.Add(new VersionConverter());
settings.Converters.Add(new LocalizedStringConverter());
diff --git a/Source/Engine/UI/ControlReference.cs b/Source/Engine/UI/ControlReference.cs
index dba3a3397..0bcd54374 100644
--- a/Source/Engine/UI/ControlReference.cs
+++ b/Source/Engine/UI/ControlReference.cs
@@ -1,84 +1,183 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Runtime.CompilerServices;
using FlaxEngine.GUI;
-namespace FlaxEngine;
-
-///
-/// Interface for control references access.
-///
-public interface IControlReference
+namespace FlaxEngine
{
///
- /// Gets or sets the reference to actor.
+ /// Interface for control references access.
///
- public UIControl UIControl { get; set; }
+ public interface IControlReference
+ {
+ ///
+ /// Gets or sets the reference to actor.
+ ///
+ public UIControl UIControl { get; set; }
+
+ ///
+ /// Gets the type of the control the interface uses.
+ ///
+ public Type ControlType { get; }
+ }
///
- /// Gets the type of the control the interface uses.
+ /// UI Control reference utility. References UI Control actor with a typed control type.
///
- public Type ControlType { get; }
+ /// Type of the UI control object.
+#if FLAX_EDITOR
+ [TypeConverter(typeof(TypeConverters.ControlReferenceConverter))]
+#endif
+ public struct ControlReference : IControlReference, IComparable, IComparable>, IEquatable> where T : Control
+ {
+ private UIControl _uiControl;
+
+ ///
+ /// Gets the typed UI control object owned by the referenced actor.
+ ///
+ [HideInEditor]
+ public T Control
+ {
+ get
+ {
+ if (_uiControl != null && _uiControl.Control is T t)
+ return t;
+ Debug.Write(LogType.Warning, "Trying to get Control from ControlReference but UIControl is null, or UIControl.Control is null, or UIControl.Control is not the correct type.");
+ return null;
+ }
+ }
+
+ ///
+ public UIControl UIControl
+ {
+ get => _uiControl;
+ set
+ {
+ if (value == null)
+ {
+ _uiControl = null;
+ }
+ else if (value.Control is T t)
+ {
+ _uiControl = value;
+ }
+ else
+ {
+ Debug.Write(LogType.Warning, "Trying to set ControlReference but UIControl.Control is null or UIControl.Control is not the correct type.");
+ }
+ }
+ }
+
+ ///
+ public Type ControlType => typeof(T);
+
+ ///
+ public override string ToString()
+ {
+ return _uiControl?.ToString() ?? "null";
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return _uiControl?.GetHashCode() ?? 0;
+ }
+
+ ///
+ public int CompareTo(object obj)
+ {
+ if (obj is IControlReference other)
+ return CompareTo(other);
+ return 0;
+ }
+
+ ///
+ public int CompareTo(ControlReference other)
+ {
+ return _uiControl == other._uiControl ? 0 : 1;
+ }
+
+ ///
+ public bool Equals(ControlReference other)
+ {
+ return _uiControl == other._uiControl;
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ return obj is ControlReference other && _uiControl == other._uiControl;
+ }
+
+ ///
+ /// The implicit operator for the Control.
+ ///
+ /// The control reference.
+ /// The control object.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator T(ControlReference reference) => reference.Control;
+
+ ///
+ /// The implicit operator for the UIControl.
+ ///
+ /// The control reference.
+ /// The control actor.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator UIControl(ControlReference reference) => reference.UIControl;
+
+ ///
+ /// Checks if the object exists (reference is not null and the unmanaged object pointer is valid).
+ ///
+ /// The object to check.
+ /// True if object is valid, otherwise false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator bool(ControlReference obj) => obj._uiControl;
+
+ ///
+ /// Checks whether the two objects are equal.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(ControlReference left, ControlReference right) => left._uiControl == right._uiControl;
+
+ ///
+ /// Checks whether the two objects are not equal.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(ControlReference left, ControlReference right) => left._uiControl != right._uiControl;
+ }
}
-///
-/// UI Control reference utility. References UI Control actor with a typed control type.
-///
-[Serializable]
-public struct ControlReference : IControlReference where T : Control
+#if FLAX_EDITOR
+namespace FlaxEngine.TypeConverters
{
- private UIControl _uiControl;
-
- ///
- /// Gets the typed UI control object owned by the referenced actor.
- ///
- [HideInEditor]
- public T Control
+ internal class ControlReferenceConverter : TypeConverter
{
- get
+ ///
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
- if (_uiControl != null && _uiControl.Control is T t)
- return t;
- Debug.Write(LogType.Warning, "Trying to get Control from ControlReference but UIControl is null, or UIControl.Control is null, or UIControl.Control is not the correct type.");
- return null;
+ if (value is string valueStr)
+ {
+ var result = Activator.CreateInstance(destinationType);
+ if (result is IControlReference control)
+ {
+ Json.JsonSerializer.ParseID(valueStr, out var id);
+ control.UIControl = Object.Find(ref id);
+ }
+ return result;
+ }
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType.Name.StartsWith("ControlReference", StringComparison.Ordinal))
+ return true;
+ return base.CanConvertTo(context, destinationType);
}
}
-
- ///
- public UIControl UIControl
- {
- get => _uiControl;
- set
- {
- if (value == null)
- {
- _uiControl = null;
- }
- else if (value.Control is T t)
- {
- _uiControl = value;
- }
- else
- {
- Debug.Write(LogType.Warning, "Trying to set ControlReference but UIControl.Control is null or UIControl.Control is not the correct type.");
- }
- }
- }
-
- ///
- public Type ControlType => typeof(T);
-
- ///
- /// The implicit operator for the Control.
- ///
- /// The ControlReference
- /// The Control.
- public static implicit operator T(ControlReference reference) => reference.Control;
-
- ///
- /// The implicit operator for the UIControl
- ///
- /// The ControlReference
- /// The UIControl.
- public static implicit operator UIControl(ControlReference reference) => reference.UIControl;
}
+#endif