using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Unity.Properties;
using UnityEngine.UIElements;
namespace Uigenx.Binding
{
///
/// Base class for hand written data sources. Derive from it, mark bindable members with
/// [CreateProperty] and call from every setter. Unity's runtime
/// binding reads the members directly; is what the studio bridge
/// and the UI Creator binder use.
///
public abstract class UgxDataSource : IUgxDataSource, INotifyBindablePropertyChanged, IDataSourceViewHashProvider
{
long _version;
public event EventHandler propertyChanged;
public long GetViewHashCode() => _version;
/// Raises the change notification for the calling property and bumps the view hash.
protected void Notify([CallerMemberName] string property = null)
{
if (string.IsNullOrEmpty(property)) return;
_version++;
// Bindings are foreign code from the source's point of view.
try
{
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));
}
catch (Exception e)
{
UnityEngine.Debug.LogError("[ugx] a property change listener threw: " + e);
}
}
///
/// Announces that everything changed. Listeners read the empty path as "refresh all", so
/// this cannot go through , which ignores an empty name.
///
protected void NotifyAll()
{
_version++;
try
{
propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(string.Empty));
}
catch (Exception e)
{
UnityEngine.Debug.LogError("[ugx] a property change listener threw: " + e);
}
}
public virtual bool TryGet(string path, out object value)
{
var container = (object)this;
return PropertyContainer.TryGetValue(ref container, UgxPropertyPaths.Get(path), out value);
}
public virtual bool TrySet(string path, object value)
{
var container = (object)this;
if (!PropertyContainer.TrySetValue(ref container, UgxPropertyPaths.Get(path), value)) return false;
_version++;
Notify(path);
return true;
}
public virtual IEnumerable Paths
{
get
{
foreach (var entry in UgxSchemaWalker.Collect(GetType())) yield return entry.Path;
}
}
}
}