288 lines
6.9 KiB
C#
288 lines
6.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using KitsuneCafe.Extension;
|
|
using KitsuneCafe.Sys;
|
|
using ObservableCollections;
|
|
using Unity.AppUI.MVVM;
|
|
using Unity.Properties;
|
|
using UnityEditor;
|
|
using UnityEditor.UIElements;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace KitsuneCafe.SOAP
|
|
{
|
|
[ObservableObject]
|
|
public partial class DatabaseModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider
|
|
{
|
|
private readonly ObservableList<IDatabase> databases = new();
|
|
public IReadOnlyObservableList<IDatabase> Databases => databases;
|
|
|
|
public DatabaseModel()
|
|
{
|
|
RefreshDatabaseCache();
|
|
}
|
|
|
|
public void RefreshDatabaseCache()
|
|
{
|
|
OnPropertyChanging(nameof(Databases));
|
|
this.databases.Clear();
|
|
|
|
var databases = AssetDatabase.FindAssets(
|
|
$"t:{typeof(Database<>).Name} a:assets",
|
|
new[] { "Assets/" }
|
|
)
|
|
.Select(AssetDatabase.GUIDToAssetPath)
|
|
.Select(path => AssetDatabase.LoadAssetAtPath(path, typeof(IDatabase)))
|
|
.Cast<IDatabase>();
|
|
|
|
this.databases.AddRange(databases);
|
|
OnPropertyChanged(nameof(Databases));
|
|
}
|
|
|
|
public long GetViewHashCode()
|
|
{
|
|
return databases.GetHashCode();
|
|
}
|
|
}
|
|
|
|
[ObservableObject]
|
|
public partial class DatabaseEditorViewModel
|
|
{
|
|
[ObservableProperty]
|
|
[AlsoNotifyChangeFor(nameof(Rows))]
|
|
private IOption<IDatabase> selected = Option.None<IDatabase>();
|
|
|
|
[CreateProperty(ReadOnly = true)]
|
|
public IEnumerable<object> Rows => selected.MapOr(
|
|
Enumerable.Empty<object>(),
|
|
db => ((dynamic)db).Rows
|
|
);
|
|
|
|
private readonly DatabaseModel model;
|
|
|
|
public DatabaseEditorViewModel(DatabaseModel model)
|
|
{
|
|
this.model = model;
|
|
}
|
|
|
|
[ICommand]
|
|
private void Select(IDatabase database)
|
|
{
|
|
Selected = Option.Some(database);
|
|
}
|
|
|
|
[ICommand]
|
|
private void Refresh()
|
|
{
|
|
model.RefreshDatabaseCache();
|
|
}
|
|
}
|
|
|
|
[ObservableObject]
|
|
public partial class DatabaseListViewModel : INotifyBindablePropertyChanged, IDataSourceViewHashProvider
|
|
{
|
|
private readonly DatabaseModel model;
|
|
|
|
[ObservableProperty]
|
|
private List<IDatabase> databases;
|
|
|
|
public DatabaseListViewModel(DatabaseModel model)
|
|
{
|
|
this.model = model;
|
|
databases = model.Databases.ToList();
|
|
}
|
|
|
|
public long GetViewHashCode()
|
|
{
|
|
return databases.GetHashCode();
|
|
}
|
|
}
|
|
|
|
[UxmlElement]
|
|
public partial class DatabaseListView : ListView
|
|
{
|
|
private readonly DatabaseListViewModel viewModel;
|
|
|
|
public event Action<IDatabase> DatabaseSelected = delegate { };
|
|
|
|
public DatabaseListView(DatabaseListViewModel viewModel) : this()
|
|
{
|
|
this.viewModel = viewModel;
|
|
dataSource = viewModel;
|
|
|
|
var binding = new DataBinding
|
|
{
|
|
dataSourcePath = PropertyPath.FromName(nameof(DatabaseListViewModel.Databases))
|
|
};
|
|
|
|
binding.sourceToUiConverters.AddConverter((ref IReadOnlyObservableList<IDatabase> xs) => (IList)xs.ToList());
|
|
SetBinding(nameof(itemsSource), binding);
|
|
}
|
|
|
|
public DatabaseListView() : base()
|
|
{
|
|
makeItem = MakeItem;
|
|
bindItem = BindItem;
|
|
unbindItem = UnbindItem;
|
|
selectionChanged += OnSelectedItem;
|
|
}
|
|
|
|
private void OnSelectedItem(IEnumerable<object> enumerable)
|
|
{
|
|
DatabaseSelected.Invoke((IDatabase)selectedItem);
|
|
}
|
|
|
|
private void UnbindItem(VisualElement element, int index)
|
|
{
|
|
}
|
|
|
|
private void BindItem(VisualElement element, int index)
|
|
{
|
|
if (element is Label label)
|
|
{
|
|
label.text = viewModel.Databases[index].Name;
|
|
}
|
|
}
|
|
|
|
private VisualElement MakeItem()
|
|
{
|
|
return new Label();
|
|
}
|
|
}
|
|
|
|
public class DatabaseItemEditorView : VisualElement
|
|
{
|
|
private SerializedObject serializedObject;
|
|
|
|
[CreateProperty]
|
|
public SerializedObject SerializedObject
|
|
{
|
|
get => serializedObject;
|
|
set
|
|
{
|
|
if (serializedObject != value)
|
|
{
|
|
serializedObject = value;
|
|
Rebuild();
|
|
}
|
|
}
|
|
}
|
|
|
|
public DatabaseItemEditorView()
|
|
{
|
|
}
|
|
|
|
public void Rebuild()
|
|
{
|
|
if (serializedObject == null) { return; }
|
|
foreach (var property in serializedObject.Enumerate())
|
|
{
|
|
Add(new PropertyField(property));
|
|
}
|
|
}
|
|
}
|
|
|
|
public class DatabaseEditorView : VisualElement
|
|
{
|
|
private readonly DatabaseEditorViewModel viewModel;
|
|
|
|
public DatabaseEditorView(
|
|
DatabaseEditorViewModel viewModel,
|
|
DatabaseListView databaseListView
|
|
)
|
|
{
|
|
this.viewModel = viewModel;
|
|
|
|
var toolbar = new Toolbar();
|
|
var refresh = new ToolbarButton(viewModel.RefreshCommand.Execute)
|
|
{
|
|
text = "Refresh"
|
|
};
|
|
|
|
toolbar.Add(refresh);
|
|
Add(toolbar);
|
|
|
|
var container = new VisualElement();
|
|
container.style.flexDirection = FlexDirection.Row;
|
|
databaseListView.DatabaseSelected += viewModel.SelectCommand.Execute;
|
|
container.Add(databaseListView);
|
|
|
|
var rowListView = new ListView
|
|
{
|
|
dataSource = viewModel,
|
|
makeItem = () => new Label(),
|
|
bindItem = (ve, i) => ((Label)ve).text = ((UnityEngine.Object)viewModel.Rows.ElementAt(i)).name
|
|
};
|
|
|
|
var itemsBinding = new DataBinding
|
|
{
|
|
dataSourcePath = PropertyPath.FromName(nameof(DatabaseEditorViewModel.Rows))
|
|
};
|
|
|
|
rowListView.SetBinding(
|
|
nameof(ListView.itemsSource),
|
|
itemsBinding
|
|
);
|
|
|
|
container.Add(rowListView);
|
|
|
|
var editor = new DatabaseItemEditorView
|
|
{
|
|
dataSource = rowListView
|
|
};
|
|
|
|
var selectedBinding = new DataBinding
|
|
{
|
|
dataSourcePath = PropertyPath.FromName(nameof(ListView.selectedItem))
|
|
};
|
|
|
|
selectedBinding.sourceToUiConverters.AddConverter(
|
|
(ref object selected) => selected == null
|
|
? null
|
|
: new SerializedObject((UnityEngine.Object)selected)
|
|
);
|
|
|
|
editor.SetBinding(
|
|
nameof(DatabaseItemEditorView.SerializedObject),
|
|
selectedBinding
|
|
);
|
|
|
|
Add(editor);
|
|
|
|
Add(container);
|
|
}
|
|
}
|
|
|
|
public class DatabaseEditorWindow : EditorWindow
|
|
{
|
|
public static Lazy<IServiceProvider> provider = new(() =>
|
|
{
|
|
var services = new ServiceCollection();
|
|
services.AddSingleton<DatabaseModel>()
|
|
.AddTransient<DatabaseEditorViewModel>()
|
|
.AddTransient<DatabaseListViewModel>()
|
|
.AddTransient<DatabaseEditorView>()
|
|
.AddTransient<DatabaseListView>();
|
|
|
|
return services.BuildServiceProvider();
|
|
});
|
|
|
|
[MenuItem("Tools/KitsuneCafe/Database")]
|
|
public static void Init()
|
|
{
|
|
DatabaseEditorWindow wnd = GetWindow<DatabaseEditorWindow>();
|
|
wnd.titleContent = new GUIContent("Database");
|
|
|
|
Vector2 size = new(800, 600);
|
|
wnd.minSize = size;
|
|
}
|
|
|
|
public void CreateGUI()
|
|
{
|
|
rootVisualElement.Add(provider.Value.GetRequiredService<DatabaseEditorView>());
|
|
}
|
|
}
|
|
}
|