diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs index c5c1ee6b0..0523904e5 100644 --- a/Source/Editor/CustomEditors/Editors/TagEditor.cs +++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs @@ -55,8 +55,8 @@ namespace FlaxEditor.CustomEditors.Editors { if (Values[0] is Tag asTag) return asTag; - if (Values[0] is int asInt) - return new Tag(asInt); + if (Values[0] is uint asUInt) + return new Tag(asUInt); if (Values[0] is string asString) return Tags.Get(asString); return Tag.Default; @@ -65,7 +65,7 @@ namespace FlaxEditor.CustomEditors.Editors { if (Values[0] is Tag) SetValue(value); - if (Values[0] is int) + if (Values[0] is uint) SetValue(value.Index); else if (Values[0] is string) SetValue(value.ToString()); @@ -114,7 +114,7 @@ namespace FlaxEditor.CustomEditors.Editors private static void GetTags(TreeNode n, PickerData pickerData) { if (n is TreeNodeWithAddons a && a.Addons.Count != 0 && a.Addons[0] is CheckBox c && c.Checked) - pickerData.CachedTags.Add(new Tag((int)n.Tag)); + pickerData.CachedTags.Add(new Tag((uint)n.Tag)); foreach (var child in n.Children) { if (child is TreeNode treeNode) @@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors.Editors if (pickerData.IsSingle) { UncheckAll(node.ParentTree, node); - var value = new Tag(c.Checked ? (int)node.Tag : -1); + var value = new Tag(c.Checked ? (uint)node.Tag : 0); pickerData.SetValue?.Invoke(value); pickerData.SetValues?.Invoke(new[] { value }); } @@ -283,7 +283,8 @@ namespace FlaxEditor.CustomEditors.Editors for (var i = 0; i < tags.Length; i++) { var tag = tags[i]; - bool isSelected = pickerData.IsSingle ? value.Index == i : values.Contains(new Tag(i)); + var tagValue = new Tag((uint)(i + 1)); + bool isSelected = pickerData.IsSingle ? value == tagValue : values.Contains(tagValue); // Count parent tags count int indentation = 0; @@ -296,7 +297,7 @@ namespace FlaxEditor.CustomEditors.Editors // Create node var node = new TreeNodeWithAddons { - Tag = i, + Tag = tagValue.Index, Text = tag, ChildrenIndent = nodeIndent, CullChildren = false, diff --git a/Source/Engine/Level/Tags.cpp b/Source/Engine/Level/Tags.cpp index 67633df9e..21cd69c08 100644 --- a/Source/Engine/Level/Tags.cpp +++ b/Source/Engine/Level/Tags.cpp @@ -12,7 +12,8 @@ FLAXENGINE_API String* TagsListDebug = nullptr; const String& Tag::ToString() const { - return Index >= 0 && Index < Tags::List.Count() ? Tags::List.Get()[Index] : String::Empty; + const int32 index = (int32)Index - 1; + return index >= 0 && index < Tags::List.Count() ? Tags::List.Get()[index] : String::Empty; } bool Tag::operator==(const StringView& other) const @@ -27,7 +28,7 @@ bool Tag::operator!=(const StringView& other) const void FLAXENGINE_API Serialization::Serialize(ISerializable::SerializeStream& stream, const Tag& v, const void* otherObj) { - if (v.Index != -1) + if (v.Index != 0) stream.String(v.ToString()); else stream.String("", 0); @@ -42,11 +43,11 @@ Tag Tags::Get(const StringView& tagName) { if (tagName.IsEmpty()) return Tag(); - Tag tag = List.Find(tagName); - if (tag.Index == -1 && tagName.HasChars()) + Tag tag(List.Find(tagName) + 1); + if (tag.Index == 0 && tagName.HasChars()) { - tag.Index = List.Count(); List.AddOne() = tagName; + tag.Index = List.Count(); #if !BUILD_RELEASE TagsListDebug = List.Get(); #endif @@ -56,7 +57,7 @@ Tag Tags::Get(const StringView& tagName) bool Tags::HasTag(const Array& list, const Tag& tag) { - if (tag.Index == -1) + if (tag.Index == 0) return false; const String& tagName = tag.ToString(); for (const Tag& e : list) @@ -70,7 +71,7 @@ bool Tags::HasTag(const Array& list, const Tag& tag) bool Tags::HasTagExact(const Array& list, const Tag& tag) { - if (tag.Index == -1) + if (tag.Index == 0) return false; return list.Contains(tag); } @@ -119,7 +120,7 @@ bool Tags::HasAllExact(const Array& list, const Array& tags) return true; } -const String& Tags::GetTagName(int32 tag) +const String& Tags::GetTagName(uint32 tag) { return Tag(tag).ToString(); } diff --git a/Source/Engine/Level/Tags.cs b/Source/Engine/Level/Tags.cs index b4aa3468c..8f46d2f85 100644 --- a/Source/Engine/Level/Tags.cs +++ b/Source/Engine/Level/Tags.cs @@ -1,33 +1,29 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System; +using System.ComponentModel; +using System.Globalization; using System.Runtime.CompilerServices; namespace FlaxEngine { + [TypeConverter(typeof(TypeConverters.TagConverter))] partial struct Tag : IEquatable, IEquatable, IComparable, IComparable, IComparable { /// /// The default . /// - public static Tag Default => new Tag(-1); + public static Tag Default => new Tag(0); /// /// Initializes a new instance of the struct. /// /// The tag index. - public Tag(int index) + public Tag(uint index) { Index = index; } - [System.Runtime.Serialization.OnDeserializing] - internal void OnDeserializing(System.Runtime.Serialization.StreamingContext context) - { - // Initialize structure with default values to replicate C++ deserialization behavior - Index = -1; - } - /// /// Compares two tags. /// @@ -50,6 +46,28 @@ namespace FlaxEngine return left.Index == right.Index; } + /// + /// Compares two tags. + /// + /// The lft tag. + /// The right tag name. + /// True if both values are equal, otherwise false. + public static bool operator ==(Tag left, string right) + { + return string.Equals(left.ToString(), right, StringComparison.Ordinal); + } + + /// + /// Compares two tags. + /// + /// The lft tag. + /// The right tag name. + /// True if both values are not equal, otherwise false. + public static bool operator !=(Tag left, string right) + { + return !string.Equals(left.ToString(), right, StringComparison.Ordinal); + } + /// /// Checks if tag is valid. /// @@ -58,7 +76,7 @@ namespace FlaxEngine [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator bool(Tag tag) { - return tag.Index != -1; + return tag.Index != 0; } /// @@ -104,7 +122,7 @@ namespace FlaxEngine /// public override int GetHashCode() { - return Index; + return (int)Index; } /// @@ -124,7 +142,7 @@ namespace FlaxEngine /// True if given tag is contained by the list of tags. Returns false for empty list. public static bool HasTag(this Tag[] list, Tag tag) { - if (tag.Index == -1) + if (tag.Index == 0) return false; string tagName = tag.ToString(); foreach (Tag e in list) @@ -144,7 +162,7 @@ namespace FlaxEngine /// True if given tag is contained by the list of tags. Returns false for empty list. public static bool HasTagExact(this Tag[] list, Tag tag) { - if (tag.Index == -1) + if (tag.Index == 0) return false; if (list == null) return false; @@ -233,3 +251,40 @@ namespace FlaxEngine } } } + +namespace FlaxEngine.TypeConverters +{ + internal class TagConverter : TypeConverter + { + /// + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + return base.CanConvertFrom(context, sourceType); + } + + /// + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string str) + { + if (str.Length == 0) + return Tag.Default; + return Tags.Get(str); + } + return base.ConvertFrom(context, culture, value); + } + + /// + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string)) + { + var v = (Tag)value; + return v.ToString(); + } + return base.ConvertTo(context, culture, value, destinationType); + } + } +} diff --git a/Source/Engine/Level/Tags.h b/Source/Engine/Level/Tags.h index eda44e224..fac49598d 100644 --- a/Source/Engine/Level/Tags.h +++ b/Source/Engine/Level/Tags.h @@ -14,9 +14,9 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API Tag DECLARE_SCRIPTING_TYPE_MINIMAL(Tag); /// - /// Index of the tag (in global Level.Tags list). + /// Index of the tag (in global Level.Tags list). Index 0 is invalid. 1 is the first index. /// - API_FIELD() int32 Index = -1; + API_FIELD() uint32 Index = 0; /// /// Gets the tag name. @@ -26,14 +26,14 @@ API_STRUCT(NoDefault) struct FLAXENGINE_API Tag public: Tag() = default; - FORCE_INLINE Tag(int32 index) + FORCE_INLINE explicit Tag(uint32 index) : Index(index) { } FORCE_INLINE operator bool() const { - return Index != -1; + return Index != 0; } FORCE_INLINE bool operator==(const Tag& other) const @@ -142,7 +142,7 @@ public: static bool HasAllExact(const Array& list, const Array& tags); private: - API_FUNCTION(NoProxy) static const String& GetTagName(int32 tag); + API_FUNCTION(NoProxy) static const String& GetTagName(uint32 tag); }; #if !BUILD_RELEASE