From ce136047e1d70c239ba252a9df5d4566c669e3d1 Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Tue, 28 Apr 2026 17:26:56 -0400 Subject: [PATCH 1/7] Upgrade InventoryPropertyDrawer to UxmlSerializedDataPropertyDrawer Replaces the PropertyDrawer base class with UxmlSerializedDataPropertyDrawer, which handles serialized object binding automatically. The CreatePropertyGUI override is replaced by CreateChildPropertiesGUI, instance fields are removed, and SerializedProperty is passed explicitly to all helper methods instead. Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/InventoryPropertyDrawer.cs | 117 ++++++++---------- 1 file changed, 53 insertions(+), 64 deletions(-) diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index 49f35a5..925c875 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -1,28 +1,22 @@ -// When you add a UxmlObject to the inventory list, include an instance of UxmlSerializedData, not an Item. -// To simplify this process, this example uses `UxmlSerializedDataCreator.CreateUxmlSerializedData`, -// a utility method that creates a UxmlObject’s UxmlSerializedData with default values. +// When you add a UxmlObject to the inventory list, include an instance of UxmlSerializedData, not an Item. +// To simplify this process, this example uses `UxmlSerializedDataCreator.CreateUxmlSerializedData`, +// a utility method that creates a UxmlObject's UxmlSerializedData with default values. // -// In this approach, the assignment of an ID value is introduced. To manage this, the last used ID value is stored -// within the element as a hidden field labeled `nextItemId`. Additionally, buttons are incorporated to add preconfigured +// In this approach, the assignment of an ID value is introduced. To manage this, the last used ID value is stored +// within the element as a hidden field labeled `nextItemId`. Additionally, buttons are incorporated to add preconfigured // sets of items. For instance, a Soldier might receive a Rifle, Machete, and Performance Pack. +using Unity.UIToolkit.Editor; using UnityEditor; using UnityEngine.UIElements; using UnityEngine; using UnityEditor.UIElements; [CustomPropertyDrawer(typeof(Inventory.UxmlSerializedData))] -public class InventoryPropertyDrawer : PropertyDrawer +public class InventoryPropertyDrawer : UxmlSerializedDataPropertyDrawer { - SerializedProperty m_InventoryProperty; - SerializedProperty m_ItemsProperty; - - public override VisualElement CreatePropertyGUI(SerializedProperty property) + protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) { - m_InventoryProperty = property; - - var root = new VisualElement(); - - m_ItemsProperty = property.FindPropertyRelative("items"); + var itemsProperty = property.FindPropertyRelative("items"); var items = new ListView { showAddRemoveFooter = true, @@ -31,52 +25,44 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property) reorderable = true, virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight, reorderMode = ListViewReorderMode.Animated, - bindingPath = m_ItemsProperty.propertyPath, - overridingAddButtonBehavior = OnAddItem + bindingPath = itemsProperty.propertyPath, + overridingAddButtonBehavior = (baseListView, button) => OnAddItem(property, baseListView, button) }; - root.Add(items); + container.Add(items); - var addSniperGear = new Button(() => + container.Add(new Button(() => { - AddGun("Rifle", 4.5f, 33, 30, 30); - AddSword("Knife", 0.5f, 7); - AddHealthPack(); - m_InventoryProperty.serializedObject.ApplyModifiedProperties(); - }); - addSniperGear.text = "Add Sniper Gear"; + AddGun(property, "Rifle", 4.5f, 33, 30, 30); + AddSword(property, "Knife", 0.5f, 7); + AddHealthPack(property); + property.serializedObject.ApplyModifiedProperties(); + }) { text = "Add Sniper Gear" }); - var addWarriorGear = new Button(() => + container.Add(new Button(() => { - AddGun("Rifle", 4.5f, 33, 30, 30); - AddHealthPack(); - AddSword("Machete", 1, 11); - m_InventoryProperty.serializedObject.ApplyModifiedProperties(); - }); - addWarriorGear.text = "Add Warrior Gear"; + AddGun(property, "Rifle", 4.5f, 33, 30, 30); + AddHealthPack(property); + AddSword(property, "Machete", 1, 11); + property.serializedObject.ApplyModifiedProperties(); + }) { text = "Add Warrior Gear" }); - var addMedicGear = new Button(() => + container.Add(new Button(() => { - AddGun("Pistol", 1.5f, 10, 15, 15); - AddHealthPack(); - AddHealthPack(); - AddHealthPack(); - m_InventoryProperty.serializedObject.ApplyModifiedProperties(); - }); - addMedicGear.text = "Add Medic Gear"; - - root.Add(addSniperGear); - root.Add(addWarriorGear); - root.Add(addMedicGear); - root.Bind(property.serializedObject); - return root; + AddGun(property, "Pistol", 1.5f, 10, 15, 15); + AddHealthPack(property); + AddHealthPack(property); + AddHealthPack(property); + property.serializedObject.ApplyModifiedProperties(); + }) { text = "Add Medic Gear" }); } - void AddGun(string name, float weight, float damage, int ammo, int maxAmmo) + void AddGun(SerializedProperty property, string name, float weight, float damage, int ammo, int maxAmmo) { - m_ItemsProperty.arraySize++; - var newItem = m_ItemsProperty.GetArrayElementAtIndex(m_ItemsProperty.arraySize - 1); + var itemsProperty = property.FindPropertyRelative("items"); + itemsProperty.arraySize++; + var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(Gun)); - newItem.FindPropertyRelative("id").intValue = NextItemId(); + newItem.FindPropertyRelative("id").intValue = NextItemId(property); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("damage").floatValue = damage; @@ -85,28 +71,30 @@ void AddGun(string name, float weight, float damage, int ammo, int maxAmmo) ammoInstance.FindPropertyRelative("maxCount").intValue = maxAmmo; } - void AddSword(string name, float weight, float damage) + void AddSword(SerializedProperty property, string name, float weight, float damage) { - m_ItemsProperty.arraySize++; - var newItem = m_ItemsProperty.GetArrayElementAtIndex(m_ItemsProperty.arraySize - 1); + var itemsProperty = property.FindPropertyRelative("items"); + itemsProperty.arraySize++; + var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(Sword)); - newItem.FindPropertyRelative("id").intValue = NextItemId(); + newItem.FindPropertyRelative("id").intValue = NextItemId(property); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("slashDamage").floatValue = damage; } - void AddHealthPack() + void AddHealthPack(SerializedProperty property) { - m_ItemsProperty.arraySize++; - var newItem = m_ItemsProperty.GetArrayElementAtIndex(m_ItemsProperty.arraySize - 1); + var itemsProperty = property.FindPropertyRelative("items"); + itemsProperty.arraySize++; + var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(HealthPack)); - newItem.FindPropertyRelative("id").intValue = NextItemId(); + newItem.FindPropertyRelative("id").intValue = NextItemId(property); } - int NextItemId() => m_InventoryProperty.FindPropertyRelative("nextItemId").intValue++; + int NextItemId(SerializedProperty property) => property.FindPropertyRelative("nextItemId").intValue++; - void OnAddItem(BaseListView baseListView, Button button) + void OnAddItem(SerializedProperty property, BaseListView baseListView, Button button) { var menu = new GenericMenu(); var items = TypeCache.GetTypesDerivedFrom(); @@ -117,11 +105,12 @@ void OnAddItem(BaseListView baseListView, Button button) menu.AddItem(new GUIContent(item.Name), false, () => { - m_ItemsProperty.arraySize++; - var newItem = m_ItemsProperty.GetArrayElementAtIndex(m_ItemsProperty.arraySize - 1); + var itemsProperty = property.FindPropertyRelative("items"); + itemsProperty.arraySize++; + var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(item); - newItem.FindPropertyRelative("id").intValue = NextItemId(); - m_InventoryProperty.serializedObject.ApplyModifiedProperties(); + newItem.FindPropertyRelative("id").intValue = NextItemId(property); + property.serializedObject.ApplyModifiedProperties(); }); } From 9e9162132c3c54d535fd12617873695d457bd2c8 Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Wed, 29 Apr 2026 17:23:44 -0400 Subject: [PATCH 2/7] Sync InventoryPropertyDrawer and AmmoPropertyDrawer with Unity source - Wrap ListView in UxmlAttributeFieldDecorator so the items list participates in the override and binding system - Add alignedFieldUssClassName to ammoField for correct Inspector alignment Co-Authored-By: Claude Sonnet 4.6 --- inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs | 3 ++- .../Scripts/InventoryPropertyDrawer.cs | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs index 8d9e13e..6ca1f1c 100644 --- a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs @@ -15,6 +15,7 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property) var maxCount = property.FindPropertyRelative("maxCount"); var ammoField = new IntegerField("Ammo") { isDelayed = true, bindingPath = count.propertyPath }; + ammoField.AddToClassList(IntegerField.alignedFieldUssClassName); ammoField.TrackPropertyValue(count, p => { count.intValue = Mathf.Min(p.intValue, maxCount.intValue); @@ -35,4 +36,4 @@ public override VisualElement CreatePropertyGUI(SerializedProperty property) return root; } -} \ No newline at end of file +} diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index 925c875..c1eca28 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -28,7 +28,11 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial bindingPath = itemsProperty.propertyPath, overridingAddButtonBehavior = (baseListView, button) => OnAddItem(property, baseListView, button) }; - container.Add(items); + + var listViewDecorator = new UxmlAttributeFieldDecorator(); + listViewDecorator.Add(items); + + container.Add(listViewDecorator); container.Add(new Button(() => { @@ -116,4 +120,4 @@ void OnAddItem(SerializedProperty property, BaseListView baseListView, Button bu menu.DropDown(button.worldBound); } -} \ No newline at end of file +} From e5973099f489f721f7b3a2a0f28ee017b5b9635a Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Thu, 30 Apr 2026 06:58:13 -0400 Subject: [PATCH 3/7] Sync inventory-property-drawers with Unity source - Add GunPropertyDrawer.cs and SwordPropertyDrawer.cs with item type labels - Add GunDrawer.uxml and InventoryDrawer.uxml UXML templates - Update InventoryPropertyDrawer.cs to showcase all four patterns - Update AmmoPropertyDrawer.cs to build UI in C# (no UXML template) - Update Inventory.cs with description, maxSlots, maxWeight fields - Update HealthPack.cs (Gun) with fireRate field - Update Sniper.uxml with new attribute values Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/AmmoPropertyDrawer.cs | 43 ++++++++++---- .../Scripts/GunPropertyDrawer.cs | 47 ++++++++++++++++ .../Scripts/HealthPack.cs | 3 + .../Scripts/Inventory.cs | 9 +++ .../Scripts/InventoryPropertyDrawer.cs | 36 ++++++++---- .../Scripts/SwordPropertyDrawer.cs | 56 +++++++++++++++++++ inventory-property-drawers/UI/GunDrawer.uxml | 14 +++++ .../UI/InventoryDrawer.uxml | 12 ++++ inventory-property-drawers/UI/Sniper.uxml | 4 +- 9 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 inventory-property-drawers/Scripts/GunPropertyDrawer.cs create mode 100644 inventory-property-drawers/Scripts/SwordPropertyDrawer.cs create mode 100644 inventory-property-drawers/UI/GunDrawer.uxml create mode 100644 inventory-property-drawers/UI/InventoryDrawer.uxml diff --git a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs index 6ca1f1c..2d52e71 100644 --- a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs @@ -1,4 +1,7 @@ -// Note that this example creates a PropertyDrawer for the Ammo type because it's not a UxmlObject. +// AmmoPropertyDrawer inherits from PropertyDrawer because Ammo is a plain [Serializable] struct, +// not a UxmlObject. There is no UxmlSerializedDataPropertyView to establish a relative binding +// context, so the UI is built in C# and binding paths use absolute SerializedProperty.propertyPath +// values. A ProgressBar provides visual feedback for the current ammo fill level. using UnityEditor; using UnityEditor.UIElements; using UnityEngine; @@ -9,30 +12,48 @@ public class AmmoPropertyDrawer : PropertyDrawer { public override VisualElement CreatePropertyGUI(SerializedProperty property) { - var root = new VisualElement { style = { flexDirection = FlexDirection.Row } }; + var root = new VisualElement(); var count = property.FindPropertyRelative("count"); var maxCount = property.FindPropertyRelative("maxCount"); - var ammoField = new IntegerField("Ammo") { isDelayed = true, bindingPath = count.propertyPath }; - ammoField.AddToClassList(IntegerField.alignedFieldUssClassName); - ammoField.TrackPropertyValue(count, p => + var row = new VisualElement { style = { flexDirection = FlexDirection.Row } }; + + var countField = new IntegerField("Ammo") { isDelayed = true, bindingPath = count.propertyPath }; + countField.AddToClassList(IntegerField.alignedFieldUssClassName); + row.Add(countField); + row.Add(new Label("/") { style = { marginLeft = 2, marginRight = 2 } }); + + var maxCountField = new IntegerField { isDelayed = true, bindingPath = maxCount.propertyPath, style = { width = 50 } }; + row.Add(maxCountField); + root.Add(row); + + var ammoBar = new ProgressBar(); + root.Add(ammoBar); + + void UpdateBar() + { + ammoBar.highValue = Mathf.Max(maxCount.intValue, 1); + ammoBar.value = count.intValue; + ammoBar.title = $"{count.intValue}/{maxCount.intValue}"; + } + + countField.TrackPropertyValue(count, p => { count.intValue = Mathf.Min(p.intValue, maxCount.intValue); property.serializedObject.ApplyModifiedProperties(); + UpdateBar(); }); - root.Add(ammoField); - root.Add(new Label("/")); - var countField = new IntegerField { isDelayed = true, bindingPath = maxCount.propertyPath }; - countField.TrackPropertyValue(maxCount, p => + maxCountField.TrackPropertyValue(maxCount, p => { - count.intValue = Mathf.Min(p.intValue, count.intValue); + count.intValue = Mathf.Min(count.intValue, p.intValue); property.serializedObject.ApplyModifiedProperties(); + UpdateBar(); }); - root.Add(countField); root.Bind(property.serializedObject); + UpdateBar(); return root; } diff --git a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs new file mode 100644 index 0000000..fbedc89 --- /dev/null +++ b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs @@ -0,0 +1,47 @@ +// GunPropertyDrawer showcases loading a UXML template inside a UxmlSerializedDataPropertyDrawer. +// The template uses UxmlAttributeField (pattern 1) and UxmlAttributeFieldDecorator (pattern 2) +// with binding-path. Because this is a UxmlSerializedDataPropertyDrawer, the binding context +// set by UxmlSerializedDataPropertyView makes those relative binding-path values resolve correctly. +// +// The ammo field is rendered by calling CreateChildPropertyGUI, which creates a UxmlAttributeField. +// UxmlAttributeField internally uses a PropertyField, which invokes AmmoPropertyDrawer and +// preserves the override indicator bar alongside the ammo count/max row and ProgressBar. +using Unity.UIToolkit.Editor; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +[CustomPropertyDrawer(typeof(Gun.UxmlSerializedData))] +public class GunPropertyDrawer : UxmlSerializedDataPropertyDrawer +{ + protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) + { + container.Add(ItemTypeLabel("Gun")); + + // Pattern 1 & 2: load a UXML template that uses UxmlAttributeField and + // UxmlAttributeFieldDecorator with binding-path for name, weight, damage, and fireRate. + var template = AssetDatabase.LoadAssetAtPath( + "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/GunDrawer.uxml"); + if (template != null) + container.Add(template.Instantiate()); + + // Render the ammo property via CreateChildPropertyGUI. The base implementation creates a + // UxmlAttributeField, which wraps a PropertyField that delegates to AmmoPropertyDrawer. + var ammoProperty = property.FindPropertyRelative("ammo"); + if (ammoProperty != null) + CreateChildPropertyGUI(container, property, ammoProperty); + } + + static Label ItemTypeLabel(string typeName) => new Label(typeName) + { + style = + { + unityFontStyleAndWeight = FontStyle.Bold, + paddingLeft = 2, + paddingBottom = 2, + marginBottom = 2, + borderBottomWidth = 1, + borderBottomColor = new Color(0.5f, 0.5f, 0.5f, 0.3f), + } + }; +} diff --git a/inventory-property-drawers/Scripts/HealthPack.cs b/inventory-property-drawers/Scripts/HealthPack.cs index 351a8e4..b02107a 100644 --- a/inventory-property-drawers/Scripts/HealthPack.cs +++ b/inventory-property-drawers/Scripts/HealthPack.cs @@ -34,6 +34,9 @@ public partial class Gun : Item [UxmlAttribute] public float damage; + [UxmlAttribute] + public float fireRate = 1; + [UxmlAttribute] public Ammo ammo = new Ammo { count = 10, maxCount = 10 }; } diff --git a/inventory-property-drawers/Scripts/Inventory.cs b/inventory-property-drawers/Scripts/Inventory.cs index 4894701..b69eba4 100644 --- a/inventory-property-drawers/Scripts/Inventory.cs +++ b/inventory-property-drawers/Scripts/Inventory.cs @@ -7,6 +7,15 @@ public partial class Inventory List m_Items = new List(); Dictionary m_ItemDictionary = new Dictionary(); + [UxmlAttribute] + public string description; + + [UxmlAttribute] + public int maxSlots = 10; + + [UxmlAttribute] + public float maxWeight = 50; + [UxmlAttribute] int nextItemId = 1; diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index c1eca28..ce8c973 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -1,10 +1,12 @@ -// When you add a UxmlObject to the inventory list, include an instance of UxmlSerializedData, not an Item. -// To simplify this process, this example uses `UxmlSerializedDataCreator.CreateUxmlSerializedData`, -// a utility method that creates a UxmlObject's UxmlSerializedData with default values. +// This drawer showcases four ways to create inspector fields for UxmlSerializedData properties: // -// In this approach, the assignment of an ID value is introduced. To manage this, the last used ID value is stored -// within the element as a hidden field labeled `nextItemId`. Additionally, buttons are incorporated to add preconfigured -// sets of items. For instance, a Soldier might receive a Rifle, Machete, and Performance Pack. +// 1. UxmlAttributeField in UXML – binding-path resolves relative to the UxmlSerializedData +// property because UxmlSerializedDataPropertyView sets up +// the binding context. +// 2. UxmlAttributeFieldDecorator in UXML – wraps an explicit field type in UXML while keeping +// the override indicator bar and context menu. +// 3. UxmlAttributeField in C# – creates a field programmatically from a SerializedProperty. +// 4. UxmlAttributeFieldDecorator in C# – wraps any IBindable element in code. using Unity.UIToolkit.Editor; using UnityEditor; using UnityEngine.UIElements; @@ -16,6 +18,18 @@ public class InventoryPropertyDrawer : UxmlSerializedDataPropertyDrawer { protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) { + // Pattern 1 & 2: load a UXML template that uses UxmlAttributeField and + // UxmlAttributeFieldDecorator with binding-path to render maxSlots and maxWeight. + // The binding paths resolve relative to this UxmlSerializedData property automatically. + var inventoryDrawer = AssetDatabase.LoadAssetAtPath( + "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/InventoryDrawer.uxml"); + if (inventoryDrawer != null) + container.Add(inventoryDrawer.Instantiate()); + + // Pattern 3: create a UxmlAttributeField in C# for the description property. + container.Add(new UxmlAttributeField(property.FindPropertyRelative("description"))); + + // Pattern 4: create a UxmlAttributeFieldDecorator in C# to wrap the items ListView. var itemsProperty = property.FindPropertyRelative("items"); var items = new ListView { @@ -31,12 +45,11 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial var listViewDecorator = new UxmlAttributeFieldDecorator(); listViewDecorator.Add(items); - container.Add(listViewDecorator); container.Add(new Button(() => { - AddGun(property, "Rifle", 4.5f, 33, 30, 30); + AddGun(property, "Rifle", 4.5f, 33, 2.5f, 30, 30); AddSword(property, "Knife", 0.5f, 7); AddHealthPack(property); property.serializedObject.ApplyModifiedProperties(); @@ -44,7 +57,7 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial container.Add(new Button(() => { - AddGun(property, "Rifle", 4.5f, 33, 30, 30); + AddGun(property, "Rifle", 4.5f, 33, 2.5f, 30, 30); AddHealthPack(property); AddSword(property, "Machete", 1, 11); property.serializedObject.ApplyModifiedProperties(); @@ -52,7 +65,7 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial container.Add(new Button(() => { - AddGun(property, "Pistol", 1.5f, 10, 15, 15); + AddGun(property, "Pistol", 1.5f, 10, 1f, 15, 15); AddHealthPack(property); AddHealthPack(property); AddHealthPack(property); @@ -60,7 +73,7 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial }) { text = "Add Medic Gear" }); } - void AddGun(SerializedProperty property, string name, float weight, float damage, int ammo, int maxAmmo) + void AddGun(SerializedProperty property, string name, float weight, float damage, float fireRate, int ammo, int maxAmmo) { var itemsProperty = property.FindPropertyRelative("items"); itemsProperty.arraySize++; @@ -70,6 +83,7 @@ void AddGun(SerializedProperty property, string name, float weight, float damage newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("damage").floatValue = damage; + newItem.FindPropertyRelative("fireRate").floatValue = fireRate; var ammoInstance = newItem.FindPropertyRelative("ammo"); ammoInstance.FindPropertyRelative("count").intValue = ammo; ammoInstance.FindPropertyRelative("maxCount").intValue = maxAmmo; diff --git a/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs b/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs new file mode 100644 index 0000000..74188d6 --- /dev/null +++ b/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs @@ -0,0 +1,56 @@ +// SwordPropertyDrawer showcases the C# approach to UxmlAttributeField and UxmlAttributeFieldDecorator. +// It overrides CreateChildPropertiesGUI to prepend a type label, then delegates to CreateChildPropertyGUI +// for each property. CreateChildPropertyGUI customizes slashDamage while letting the base class handle +// all other properties (name, weight) with the default UxmlAttributeField. +using Unity.UIToolkit.Editor; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +[CustomPropertyDrawer(typeof(Sword.UxmlSerializedData))] +public class SwordPropertyDrawer : UxmlSerializedDataPropertyDrawer +{ + protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) + { + container.Add(ItemTypeLabel("Sword")); + base.CreateChildPropertiesGUI(container, property); + } + + protected override void CreateChildPropertyGUI(VisualElement container, SerializedProperty property, + SerializedProperty childProperty) + { + if (childProperty.name == "slashDamage") + { + // Pattern 3 & 4 in C#: UxmlAttributeFieldDecorator wrapping an explicit Slider. + // This uses the same control type as the Slider in InventoryDrawer.uxml, but created + // in code rather than UXML. + var decorator = new UxmlAttributeFieldDecorator(); + var slider = new Slider(childProperty.displayName, 1, 100) + { + showInputField = true, + bindingPath = childProperty.propertyPath + }; + slider.AddToClassList(Slider.alignedFieldUssClassName); + decorator.Add(slider); + container.Add(decorator); + } + else + { + // Pattern 3: let the base class create a UxmlAttributeField for name and weight. + base.CreateChildPropertyGUI(container, property, childProperty); + } + } + + static Label ItemTypeLabel(string typeName) => new Label(typeName) + { + style = + { + unityFontStyleAndWeight = FontStyle.Bold, + paddingLeft = 2, + paddingBottom = 2, + marginBottom = 2, + borderBottomWidth = 1, + borderBottomColor = new Color(0.5f, 0.5f, 0.5f, 0.3f), + } + }; +} diff --git a/inventory-property-drawers/UI/GunDrawer.uxml b/inventory-property-drawers/UI/GunDrawer.uxml new file mode 100644 index 0000000..a3f5405 --- /dev/null +++ b/inventory-property-drawers/UI/GunDrawer.uxml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/inventory-property-drawers/UI/InventoryDrawer.uxml b/inventory-property-drawers/UI/InventoryDrawer.uxml new file mode 100644 index 0000000..57ef1d8 --- /dev/null +++ b/inventory-property-drawers/UI/InventoryDrawer.uxml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/inventory-property-drawers/UI/Sniper.uxml b/inventory-property-drawers/UI/Sniper.uxml index e51f57a..5aa537d 100644 --- a/inventory-property-drawers/UI/Sniper.uxml +++ b/inventory-property-drawers/UI/Sniper.uxml @@ -1,9 +1,9 @@ - + - + From 25cfdf7513b06f108147ef004871a4a6ecb236a6 Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Thu, 30 Apr 2026 10:44:59 -0400 Subject: [PATCH 4/7] Sync GunPropertyDrawer and InventoryPropertyDrawer with Unity source - Cache VisualTreeAsset in a static field to avoid repeated disk lookups - Extract AppendItem helper in InventoryPropertyDrawer to eliminate duplicated add/init logic - Add path-dependency comment near AssetDatabase.LoadAssetAtPath calls Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/GunPropertyDrawer.cs | 14 ++++-- .../Scripts/InventoryPropertyDrawer.cs | 47 +++++++++---------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs index fbedc89..8f4e8ab 100644 --- a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs @@ -14,16 +14,22 @@ [CustomPropertyDrawer(typeof(Gun.UxmlSerializedData))] public class GunPropertyDrawer : UxmlSerializedDataPropertyDrawer { + // Cached to avoid a disk lookup on every drawer instantiation. + // Note: the path below must match the location of the UI folder in your project. + // If you move or rename the inventory-property-drawers folder, update this path accordingly. + static VisualTreeAsset s_Template; + protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) { container.Add(ItemTypeLabel("Gun")); // Pattern 1 & 2: load a UXML template that uses UxmlAttributeField and // UxmlAttributeFieldDecorator with binding-path for name, weight, damage, and fireRate. - var template = AssetDatabase.LoadAssetAtPath( - "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/GunDrawer.uxml"); - if (template != null) - container.Add(template.Instantiate()); + if (s_Template == null) + s_Template = AssetDatabase.LoadAssetAtPath( + "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/GunDrawer.uxml"); + if (s_Template != null) + container.Add(s_Template.Instantiate()); // Render the ammo property via CreateChildPropertyGUI. The base implementation creates a // UxmlAttributeField, which wraps a PropertyField that delegates to AmmoPropertyDrawer. diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index ce8c973..51cf884 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -16,15 +16,21 @@ [CustomPropertyDrawer(typeof(Inventory.UxmlSerializedData))] public class InventoryPropertyDrawer : UxmlSerializedDataPropertyDrawer { + // Cached to avoid a disk lookup on every drawer instantiation. + // Note: the path below must match the location of the UI folder in your project. + // If you move or rename the inventory-property-drawers folder, update this path accordingly. + static VisualTreeAsset s_Template; + protected override void CreateChildPropertiesGUI(VisualElement container, SerializedProperty property) { // Pattern 1 & 2: load a UXML template that uses UxmlAttributeField and // UxmlAttributeFieldDecorator with binding-path to render maxSlots and maxWeight. // The binding paths resolve relative to this UxmlSerializedData property automatically. - var inventoryDrawer = AssetDatabase.LoadAssetAtPath( - "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/InventoryDrawer.uxml"); - if (inventoryDrawer != null) - container.Add(inventoryDrawer.Instantiate()); + if (s_Template == null) + s_Template = AssetDatabase.LoadAssetAtPath( + "Assets/ui-toolkit-manual-code-examples/inventory-property-drawers/UI/InventoryDrawer.uxml"); + if (s_Template != null) + container.Add(s_Template.Instantiate()); // Pattern 3: create a UxmlAttributeField in C# for the description property. container.Add(new UxmlAttributeField(property.FindPropertyRelative("description"))); @@ -73,13 +79,21 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial }) { text = "Add Medic Gear" }); } - void AddGun(SerializedProperty property, string name, float weight, float damage, float fireRate, int ammo, int maxAmmo) + // Appends a new item of the given type to the items array and assigns its ID. + // Returns the SerializedProperty for the new element so callers can set type-specific fields. + SerializedProperty AppendItem(SerializedProperty property, System.Type itemType) { var itemsProperty = property.FindPropertyRelative("items"); itemsProperty.arraySize++; var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); - newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(Gun)); + newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(itemType); newItem.FindPropertyRelative("id").intValue = NextItemId(property); + return newItem; + } + + void AddGun(SerializedProperty property, string name, float weight, float damage, float fireRate, int ammo, int maxAmmo) + { + var newItem = AppendItem(property, typeof(Gun)); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("damage").floatValue = damage; @@ -91,24 +105,13 @@ void AddGun(SerializedProperty property, string name, float weight, float damage void AddSword(SerializedProperty property, string name, float weight, float damage) { - var itemsProperty = property.FindPropertyRelative("items"); - itemsProperty.arraySize++; - var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); - newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(Sword)); - newItem.FindPropertyRelative("id").intValue = NextItemId(property); + var newItem = AppendItem(property, typeof(Sword)); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("slashDamage").floatValue = damage; } - void AddHealthPack(SerializedProperty property) - { - var itemsProperty = property.FindPropertyRelative("items"); - itemsProperty.arraySize++; - var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); - newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(typeof(HealthPack)); - newItem.FindPropertyRelative("id").intValue = NextItemId(property); - } + void AddHealthPack(SerializedProperty property) => AppendItem(property, typeof(HealthPack)); int NextItemId(SerializedProperty property) => property.FindPropertyRelative("nextItemId").intValue++; @@ -123,11 +126,7 @@ void OnAddItem(SerializedProperty property, BaseListView baseListView, Button bu menu.AddItem(new GUIContent(item.Name), false, () => { - var itemsProperty = property.FindPropertyRelative("items"); - itemsProperty.arraySize++; - var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); - newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(item); - newItem.FindPropertyRelative("id").intValue = NextItemId(property); + AppendItem(property, item); property.serializedObject.ApplyModifiedProperties(); }); } From f4786d4cac984a3dfa1e75d8032c8d773f1e5fc7 Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Thu, 30 Apr 2026 11:15:17 -0400 Subject: [PATCH 5/7] Sync example scripts with Unity source - Replace var with explicit types in AmmoPropertyDrawer, GunPropertyDrawer, InventoryPropertyDrawer, and SwordPropertyDrawer - Break long IntegerField initializer lines in AmmoPropertyDrawer Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/AmmoPropertyDrawer.cs | 23 +++++++++++++------ .../Scripts/GunPropertyDrawer.cs | 2 +- .../Scripts/InventoryPropertyDrawer.cs | 6 ++--- .../Scripts/SwordPropertyDrawer.cs | 4 ++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs index 2d52e71..b0203dc 100644 --- a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs @@ -12,23 +12,32 @@ public class AmmoPropertyDrawer : PropertyDrawer { public override VisualElement CreatePropertyGUI(SerializedProperty property) { - var root = new VisualElement(); + VisualElement root = new VisualElement(); - var count = property.FindPropertyRelative("count"); - var maxCount = property.FindPropertyRelative("maxCount"); + SerializedProperty count = property.FindPropertyRelative("count"); + SerializedProperty maxCount = property.FindPropertyRelative("maxCount"); - var row = new VisualElement { style = { flexDirection = FlexDirection.Row } }; + VisualElement row = new VisualElement { style = { flexDirection = FlexDirection.Row } }; - var countField = new IntegerField("Ammo") { isDelayed = true, bindingPath = count.propertyPath }; + IntegerField countField = new IntegerField("Ammo") + { + isDelayed = true, + bindingPath = count.propertyPath + }; countField.AddToClassList(IntegerField.alignedFieldUssClassName); row.Add(countField); row.Add(new Label("/") { style = { marginLeft = 2, marginRight = 2 } }); - var maxCountField = new IntegerField { isDelayed = true, bindingPath = maxCount.propertyPath, style = { width = 50 } }; + IntegerField maxCountField = new IntegerField + { + isDelayed = true, + bindingPath = maxCount.propertyPath, + style = { width = 50 } + }; row.Add(maxCountField); root.Add(row); - var ammoBar = new ProgressBar(); + ProgressBar ammoBar = new ProgressBar(); root.Add(ammoBar); void UpdateBar() diff --git a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs index 8f4e8ab..33e223c 100644 --- a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs @@ -33,7 +33,7 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial // Render the ammo property via CreateChildPropertyGUI. The base implementation creates a // UxmlAttributeField, which wraps a PropertyField that delegates to AmmoPropertyDrawer. - var ammoProperty = property.FindPropertyRelative("ammo"); + SerializedProperty ammoProperty = property.FindPropertyRelative("ammo"); if (ammoProperty != null) CreateChildPropertyGUI(container, property, ammoProperty); } diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index 51cf884..d117bf0 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -36,8 +36,8 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial container.Add(new UxmlAttributeField(property.FindPropertyRelative("description"))); // Pattern 4: create a UxmlAttributeFieldDecorator in C# to wrap the items ListView. - var itemsProperty = property.FindPropertyRelative("items"); - var items = new ListView + SerializedProperty itemsProperty = property.FindPropertyRelative("items"); + ListView items = new ListView { showAddRemoveFooter = true, showBorder = true, @@ -49,7 +49,7 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial overridingAddButtonBehavior = (baseListView, button) => OnAddItem(property, baseListView, button) }; - var listViewDecorator = new UxmlAttributeFieldDecorator(); + UxmlAttributeFieldDecorator listViewDecorator = new UxmlAttributeFieldDecorator(); listViewDecorator.Add(items); container.Add(listViewDecorator); diff --git a/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs b/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs index 74188d6..81ae734 100644 --- a/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/SwordPropertyDrawer.cs @@ -24,8 +24,8 @@ protected override void CreateChildPropertyGUI(VisualElement container, Serializ // Pattern 3 & 4 in C#: UxmlAttributeFieldDecorator wrapping an explicit Slider. // This uses the same control type as the Slider in InventoryDrawer.uxml, but created // in code rather than UXML. - var decorator = new UxmlAttributeFieldDecorator(); - var slider = new Slider(childProperty.displayName, 1, 100) + UxmlAttributeFieldDecorator decorator = new UxmlAttributeFieldDecorator(); + Slider slider = new Slider(childProperty.displayName, 1, 100) { showInputField = true, bindingPath = childProperty.propertyPath From 0115eac587b9a5ebd36442bc300ccc172108b00b Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Thu, 30 Apr 2026 11:47:53 -0400 Subject: [PATCH 6/7] Replace var with explicit types in InventoryPropertyDrawer Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/InventoryPropertyDrawer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index d117bf0..c57433b 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -83,9 +83,9 @@ protected override void CreateChildPropertiesGUI(VisualElement container, Serial // Returns the SerializedProperty for the new element so callers can set type-specific fields. SerializedProperty AppendItem(SerializedProperty property, System.Type itemType) { - var itemsProperty = property.FindPropertyRelative("items"); + SerializedProperty itemsProperty = property.FindPropertyRelative("items"); itemsProperty.arraySize++; - var newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); + SerializedProperty newItem = itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1); newItem.managedReferenceValue = UxmlSerializedDataCreator.CreateUxmlSerializedData(itemType); newItem.FindPropertyRelative("id").intValue = NextItemId(property); return newItem; @@ -93,7 +93,7 @@ SerializedProperty AppendItem(SerializedProperty property, System.Type itemType) void AddGun(SerializedProperty property, string name, float weight, float damage, float fireRate, int ammo, int maxAmmo) { - var newItem = AppendItem(property, typeof(Gun)); + SerializedProperty newItem = AppendItem(property, typeof(Gun)); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("damage").floatValue = damage; @@ -105,7 +105,7 @@ void AddGun(SerializedProperty property, string name, float weight, float damage void AddSword(SerializedProperty property, string name, float weight, float damage) { - var newItem = AppendItem(property, typeof(Sword)); + SerializedProperty newItem = AppendItem(property, typeof(Sword)); newItem.FindPropertyRelative("name").stringValue = name; newItem.FindPropertyRelative("weight").floatValue = weight; newItem.FindPropertyRelative("slashDamage").floatValue = damage; @@ -117,8 +117,8 @@ void AddSword(SerializedProperty property, string name, float weight, float dama void OnAddItem(SerializedProperty property, BaseListView baseListView, Button button) { - var menu = new GenericMenu(); - var items = TypeCache.GetTypesDerivedFrom(); + GenericMenu menu = new GenericMenu(); + TypeCache.TypeCollection items = TypeCache.GetTypesDerivedFrom(); foreach (var item in items) { if (item.IsAbstract) From ae9b7f520a169e6d7830d2197ac5f6cc83d76546 Mon Sep 17 00:00:00 2001 From: Alexandre Dzimi Mve Date: Fri, 1 May 2026 06:59:02 -0400 Subject: [PATCH 7/7] Backtick-format API and attribute names in drawer file comments Co-Authored-By: Claude Sonnet 4.6 --- .../Scripts/AmmoPropertyDrawer.cs | 8 ++++---- .../Scripts/GunPropertyDrawer.cs | 14 +++++++------- .../Scripts/InventoryPropertyDrawer.cs | 16 ++++++++-------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs index b0203dc..e921257 100644 --- a/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/AmmoPropertyDrawer.cs @@ -1,7 +1,7 @@ -// AmmoPropertyDrawer inherits from PropertyDrawer because Ammo is a plain [Serializable] struct, -// not a UxmlObject. There is no UxmlSerializedDataPropertyView to establish a relative binding -// context, so the UI is built in C# and binding paths use absolute SerializedProperty.propertyPath -// values. A ProgressBar provides visual feedback for the current ammo fill level. +// `AmmoPropertyDrawer` inherits from `PropertyDrawer` because `Ammo` is a plain `[Serializable]` struct, +// not a `UxmlObject`. There is no `UxmlSerializedDataPropertyView` to establish a relative binding +// context, so the UI is built in C# and binding paths use absolute `SerializedProperty.propertyPath` +// values. A `ProgressBar` provides visual feedback for the current ammo fill level. using UnityEditor; using UnityEditor.UIElements; using UnityEngine; diff --git a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs index 33e223c..58cc88f 100644 --- a/inventory-property-drawers/Scripts/GunPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/GunPropertyDrawer.cs @@ -1,11 +1,11 @@ -// GunPropertyDrawer showcases loading a UXML template inside a UxmlSerializedDataPropertyDrawer. -// The template uses UxmlAttributeField (pattern 1) and UxmlAttributeFieldDecorator (pattern 2) -// with binding-path. Because this is a UxmlSerializedDataPropertyDrawer, the binding context -// set by UxmlSerializedDataPropertyView makes those relative binding-path values resolve correctly. +// `GunPropertyDrawer` showcases loading a UXML template inside a `UxmlSerializedDataPropertyDrawer`. +// The template uses `UxmlAttributeField` (pattern 1) and `UxmlAttributeFieldDecorator` (pattern 2) +// with `binding-path`. Because this is a `UxmlSerializedDataPropertyDrawer`, the binding context +// set by `UxmlSerializedDataPropertyView` makes those relative `binding-path` values resolve correctly. // -// The ammo field is rendered by calling CreateChildPropertyGUI, which creates a UxmlAttributeField. -// UxmlAttributeField internally uses a PropertyField, which invokes AmmoPropertyDrawer and -// preserves the override indicator bar alongside the ammo count/max row and ProgressBar. +// The ammo field is rendered by calling `CreateChildPropertyGUI`, which creates a `UxmlAttributeField`. +// `UxmlAttributeField` internally uses a `PropertyField`, which invokes `AmmoPropertyDrawer` and +// preserves the override indicator bar alongside the ammo count/max row and `ProgressBar`. using Unity.UIToolkit.Editor; using UnityEditor; using UnityEngine; diff --git a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs index c57433b..01dc67a 100644 --- a/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs +++ b/inventory-property-drawers/Scripts/InventoryPropertyDrawer.cs @@ -1,12 +1,12 @@ -// This drawer showcases four ways to create inspector fields for UxmlSerializedData properties: +// This drawer showcases four ways to create inspector fields for `UxmlSerializedData` properties: // -// 1. UxmlAttributeField in UXML – binding-path resolves relative to the UxmlSerializedData -// property because UxmlSerializedDataPropertyView sets up -// the binding context. -// 2. UxmlAttributeFieldDecorator in UXML – wraps an explicit field type in UXML while keeping -// the override indicator bar and context menu. -// 3. UxmlAttributeField in C# – creates a field programmatically from a SerializedProperty. -// 4. UxmlAttributeFieldDecorator in C# – wraps any IBindable element in code. +// 1. `UxmlAttributeField` in UXML – `binding-path` resolves relative to the `UxmlSerializedData` +// property because `UxmlSerializedDataPropertyView` sets up +// the binding context. +// 2. `UxmlAttributeFieldDecorator` in UXML – wraps an explicit field type in UXML while keeping +// the override indicator bar and context menu. +// 3. `UxmlAttributeField` in C# – creates a field programmatically from a `SerializedProperty`. +// 4. `UxmlAttributeFieldDecorator` in C# – wraps any `IBindable` element in code. using Unity.UIToolkit.Editor; using UnityEditor; using UnityEngine.UIElements;