| | | 1 | | #nullable enable |
| | | 2 | | #if SCRIPTABLE_VALUES_RUNTIME_BINDING && SCRIPTABLE_VALUES_UITOOLKIT |
| | | 3 | | #define SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | | 4 | | #endif // SCRIPTABLE_VALUES_RUNTIME_BINDING |
| | | 5 | | |
| | | 6 | | using System.ComponentModel; |
| | | 7 | | using System.Diagnostics; |
| | | 8 | | using System.Runtime.CompilerServices; |
| | | 9 | | using Hertzole.ScriptableValues.Helpers; |
| | | 10 | | using UnityEngine.Assertions; |
| | | 11 | | #if SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | | 12 | | using System; |
| | | 13 | | using Unity.Properties; |
| | | 14 | | using UnityEngine.UIElements; |
| | | 15 | | #endif // SCRIPTABLE_VALUES_RUNTIME_BINDING |
| | | 16 | | |
| | | 17 | | namespace Hertzole.ScriptableValues |
| | | 18 | | { |
| | | 19 | | partial class RuntimeScriptableObject : |
| | | 20 | | #if SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | | 21 | | IDataSourceViewHashProvider, |
| | | 22 | | INotifyBindablePropertyChanged, |
| | | 23 | | #endif // SCRIPTABLE_VALUES_RUNTIME_BINDING |
| | | 24 | | INotifyPropertyChanging, |
| | | 25 | | INotifyPropertyChanged |
| | | 26 | | { |
| | | 27 | | private event PropertyChangingEventHandler? OnNotifyPropertyChanging; |
| | | 28 | | private event PropertyChangedEventHandler? OnNotifyPropertyChanged; |
| | | 29 | | |
| | | 30 | | event PropertyChangingEventHandler INotifyPropertyChanging.PropertyChanging |
| | | 31 | | { |
| | 9756 | 32 | | add { OnNotifyPropertyChanging += value; } |
| | 9756 | 33 | | remove { OnNotifyPropertyChanging -= value; } |
| | | 34 | | } |
| | | 35 | | event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged |
| | | 36 | | { |
| | 9756 | 37 | | add { OnNotifyPropertyChanged += value; } |
| | 9756 | 38 | | remove { OnNotifyPropertyChanged -= value; } |
| | | 39 | | } |
| | | 40 | | |
| | | 41 | | /// <summary> |
| | | 42 | | /// Invoke the <see cref="INotifyPropertyChanging.PropertyChanging" /> event with the given property name. |
| | | 43 | | /// </summary> |
| | | 44 | | /// <param name="propertyName">The name of the property that is changing.</param> |
| | | 45 | | protected void NotifyPropertyChanging([CallerMemberName] string propertyName = "") |
| | 0 | 46 | | { |
| | | 47 | | // Check first if the event is null to avoid creating a new PropertyChangingEventArgs |
| | 0 | 48 | | if (OnNotifyPropertyChanging != null) |
| | 0 | 49 | | { |
| | 0 | 50 | | NotifyPropertyChanging(new PropertyChangingEventArgs(propertyName)); |
| | 0 | 51 | | } |
| | 0 | 52 | | } |
| | | 53 | | |
| | | 54 | | /// <summary> |
| | | 55 | | /// Invokes the <see cref="INotifyPropertyChanging.PropertyChanging" /> event with the given |
| | | 56 | | /// <see cref="PropertyChangingEventArgs" />. |
| | | 57 | | /// </summary> |
| | | 58 | | /// <param name="args">The <see cref="PropertyChangingEventArgs" /> to use.</param> |
| | | 59 | | protected void NotifyPropertyChanging(PropertyChangingEventArgs args) |
| | 49890 | 60 | | { |
| | 49890 | 61 | | Assert.IsNotNull(args); |
| | | 62 | | |
| | 49890 | 63 | | OnNotifyPropertyChanging?.Invoke(this, args); |
| | 49890 | 64 | | } |
| | | 65 | | |
| | | 66 | | /// <summary> |
| | | 67 | | /// Invoke the <see cref="INotifyPropertyChanged.PropertyChanged" /> event and the |
| | | 68 | | /// <see cref="INotifyBindablePropertyChanged.propertyChanged" /> event with the given property name. |
| | | 69 | | /// </summary> |
| | | 70 | | /// <param name="propertyName">The name of the property that has changed.</param> |
| | | 71 | | protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "") |
| | 0 | 72 | | { |
| | | 73 | | // Check first if the event is null to avoid creating a new PropertyChangedEventArgs |
| | 0 | 74 | | if (OnNotifyPropertyChanged != null) |
| | 0 | 75 | | { |
| | 0 | 76 | | NotifyPropertyChanged(new PropertyChangedEventArgs(propertyName)); |
| | 0 | 77 | | } |
| | | 78 | | else |
| | 0 | 79 | | { |
| | | 80 | | // If the event is null, we can still notify Unity about the property change. |
| | | 81 | | // NotifyPropertyChanged would call this otherwise... |
| | 0 | 82 | | NotifyUnityPropertyChanged(propertyName); |
| | 0 | 83 | | } |
| | 0 | 84 | | } |
| | | 85 | | |
| | | 86 | | /// <summary> |
| | | 87 | | /// Invoke the <see cref="INotifyPropertyChanged.PropertyChanged" /> event and the |
| | | 88 | | /// <see cref="INotifyBindablePropertyChanged.propertyChanged" /> event with the given |
| | | 89 | | /// <see cref="PropertyChangedEventArgs" />. |
| | | 90 | | /// </summary> |
| | | 91 | | /// <param name="args">The <see cref="PropertyChangedEventArgs" /> to use.</param> |
| | | 92 | | protected void NotifyPropertyChanged(PropertyChangedEventArgs args) |
| | 49890 | 93 | | { |
| | 49890 | 94 | | Assert.IsNotNull(args); |
| | | 95 | | |
| | 33260 | 96 | | NotifyUnityPropertyChanged(args.PropertyName); |
| | 49890 | 97 | | OnNotifyPropertyChanged?.Invoke(this, args); |
| | 49890 | 98 | | } |
| | | 99 | | |
| | | 100 | | [Conditional("SCRIPTABLE_VALUES_DO_UI_TOOLKIT")] |
| | | 101 | | private void NotifyUnityPropertyChanged(string propertyName) |
| | 33260 | 102 | | { |
| | | 103 | | #if SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | 33260 | 104 | | OnPropertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(new BindingId(new PropertyPath(property |
| | | 105 | | #endif // SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | 33260 | 106 | | } |
| | | 107 | | |
| | | 108 | | /// <summary> |
| | | 109 | | /// Sets a field to a new value and notifies the property changed event. |
| | | 110 | | /// </summary> |
| | | 111 | | /// <remarks>Calling this will not notify any property changes if the new value is the same as the current field |
| | | 112 | | /// <param name="field">The field to set.</param> |
| | | 113 | | /// <param name="newValue">The new value to set.</param> |
| | | 114 | | /// <param name="propertyName">The name of the property that is changing.</param> |
| | | 115 | | /// <typeparam name="T">The type of the field.</typeparam> |
| | | 116 | | /// <returns><c>true</c> if the field was changed; otherwise, <c>false</c>.</returns> |
| | | 117 | | protected bool SetField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = "") |
| | 0 | 118 | | { |
| | 0 | 119 | | if (EqualityHelper.Equals(field, newValue)) |
| | 0 | 120 | | { |
| | 0 | 121 | | return false; |
| | | 122 | | } |
| | | 123 | | |
| | 0 | 124 | | PropertyChangingEventArgs? changingEventArgs = null; |
| | 0 | 125 | | PropertyChangedEventArgs? changedEventArgs = null; |
| | | 126 | | |
| | | 127 | | // Only create the event args if the event is not null |
| | 0 | 128 | | if (OnNotifyPropertyChanging != null) |
| | 0 | 129 | | { |
| | 0 | 130 | | changingEventArgs = new PropertyChangingEventArgs(propertyName); |
| | 0 | 131 | | } |
| | | 132 | | |
| | 0 | 133 | | if (OnNotifyPropertyChanged != null) |
| | 0 | 134 | | { |
| | 0 | 135 | | changedEventArgs = new PropertyChangedEventArgs(propertyName); |
| | 0 | 136 | | } |
| | | 137 | | |
| | 0 | 138 | | return SetFieldInternal(ref field, newValue, changingEventArgs, changedEventArgs, propertyName); |
| | 0 | 139 | | } |
| | | 140 | | |
| | | 141 | | /// <summary> |
| | | 142 | | /// Sets a field to a new value and notifies the property changed event. |
| | | 143 | | /// </summary> |
| | | 144 | | /// <param name="field">The field to set.</param> |
| | | 145 | | /// <param name="newValue">The new value to set.</param> |
| | | 146 | | /// <param name="changingArgs">The <see cref="PropertyChangingEventArgs" /> to use.</param> |
| | | 147 | | /// <param name="changedArgs">The <see cref="PropertyChangedEventArgs" /> to use.</param> |
| | | 148 | | /// <typeparam name="T">The type of the field.</typeparam> |
| | | 149 | | /// <returns><c>true</c> if the field was changed; otherwise, <c>false</c>.</returns> |
| | | 150 | | protected bool SetField<T>(ref T field, T newValue, PropertyChangingEventArgs changingArgs, PropertyChangedEvent |
| | 104466 | 151 | | { |
| | 104466 | 152 | | if (EqualityHelper.Equals(field, newValue)) |
| | 70068 | 153 | | { |
| | 70068 | 154 | | return false; |
| | | 155 | | } |
| | | 156 | | |
| | 34398 | 157 | | return SetFieldInternal(ref field, newValue, changingArgs, changedArgs, changedArgs.PropertyName); |
| | 104466 | 158 | | } |
| | | 159 | | |
| | | 160 | | private bool SetFieldInternal<T>(ref T field, |
| | | 161 | | T newValue, |
| | | 162 | | PropertyChangingEventArgs? changingArgs, |
| | | 163 | | PropertyChangedEventArgs? changedArgs, |
| | | 164 | | string propertyName) |
| | 34398 | 165 | | { |
| | 34398 | 166 | | Assert.IsNotNull(changingArgs); |
| | 34398 | 167 | | Assert.IsNotNull(changedArgs); |
| | | 168 | | |
| | 34398 | 169 | | if (changingArgs != null) |
| | 34398 | 170 | | { |
| | 34398 | 171 | | NotifyPropertyChanging(changingArgs); |
| | 34398 | 172 | | } |
| | | 173 | | |
| | 34398 | 174 | | field = newValue; |
| | | 175 | | |
| | 34398 | 176 | | if (changedArgs != null) |
| | 34398 | 177 | | { |
| | 34398 | 178 | | NotifyPropertyChanged(changedArgs); |
| | 34398 | 179 | | } |
| | | 180 | | else |
| | 0 | 181 | | { |
| | 0 | 182 | | NotifyUnityPropertyChanged(propertyName); |
| | 0 | 183 | | } |
| | | 184 | | |
| | 34398 | 185 | | return true; |
| | 34398 | 186 | | } |
| | | 187 | | |
| | | 188 | | /// <summary> |
| | | 189 | | /// Warns if there are any left-over subscribers to the events. |
| | | 190 | | /// </summary> |
| | | 191 | | /// <remarks>This will only be called in the Unity editor and builds with the DEBUG flag.</remarks> |
| | | 192 | | [Conditional("DEBUG")] |
| | | 193 | | protected virtual void WarnIfLeftOverSubscribers() |
| | 27276 | 194 | | { |
| | 27276 | 195 | | EventHelper.WarnIfLeftOverSubscribers(OnNotifyPropertyChanging, "INotifyPropertyChanging.PropertyChanging", |
| | 27276 | 196 | | EventHelper.WarnIfLeftOverSubscribers(OnNotifyPropertyChanged, "INotifyPropertyChanged.PropertyChanged", thi |
| | | 197 | | #if SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | 18692 | 198 | | EventHelper.WarnIfLeftOverSubscribers(OnPropertyChanged, "INotifyBindablePropertyChanged.propertyChanged", t |
| | | 199 | | #endif // SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | 27276 | 200 | | } |
| | | 201 | | |
| | | 202 | | #if SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | | 203 | | private event EventHandler<BindablePropertyChangedEventArgs>? OnPropertyChanged; |
| | | 204 | | |
| | | 205 | | event EventHandler<BindablePropertyChangedEventArgs> INotifyBindablePropertyChanged.propertyChanged |
| | | 206 | | { |
| | 2940 | 207 | | add { OnPropertyChanged += value; } |
| | 2940 | 208 | | remove { OnPropertyChanged -= value; } |
| | | 209 | | } |
| | | 210 | | |
| | | 211 | | /// <summary> |
| | | 212 | | /// Computes a hash code for the view of the data source. |
| | | 213 | | /// </summary> |
| | | 214 | | /// <returns>A hash code for the current object.</returns> |
| | | 215 | | protected virtual long GetViewHashCode() |
| | 1960 | 216 | | { |
| | 1960 | 217 | | return GetHashCode(); |
| | 1960 | 218 | | } |
| | | 219 | | |
| | | 220 | | long IDataSourceViewHashProvider.GetViewHashCode() |
| | 1960 | 221 | | { |
| | 1960 | 222 | | return GetViewHashCode(); |
| | 1960 | 223 | | } |
| | | 224 | | #endif // SCRIPTABLE_VALUES_DO_UI_TOOLKIT |
| | | 225 | | } |
| | | 226 | | } |