Add component editors and UI controls

Added the `HierarchyEditor` and `LocalToWorldEditor` classes to implement custom component editing functionality.
Added the `Vector3Field` control for 3D vector manipulation and its corresponding XAML definition.
Added the `ComponentDataView` and `ComponentObject` classes to manage component data display and access.
Added the `CustomEditorAttribute` to mark classes as custom editors for specific components.

Changed the `IInspectable` interface to use properties for `Icon`, `HeaderContent`, and `InspectorContent`.
Changed the `PropertyField` class to enhance UI control binding capabilities.
Changed the `EditorWorldManager` to improve world data loading and deserialization processes.
Changed the `EntityNode` and `WorldNode` classes to update entity construction and component querying.
Changed the `StaticResource` class to include new binding flags for component properties.
Changed the `InspectorService` to remove old contract references and adopt new interfaces.
Changed the `QueryEnumerable` and related files to update generic constraints for improved type safety.
Changed the `QueryItem` class to reflect new generic constraints and enhance deconstruction.
Changed the `World.Query` methods to utilize the updated generic constraints.

Updated the `SerializationTest` to align with new entity creation and management practices.
This commit is contained in:
2025-06-20 20:19:14 +09:00
parent fc44c73ca8
commit 1724072f7e
54 changed files with 1474 additions and 554 deletions

View File

@@ -0,0 +1,122 @@
using Ghost.Editor.Core.Inspector;
using Ghost.Editor.Resources;
using Ghost.Editor.Utilities;
using Ghost.Entities;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System.Reflection;
namespace Ghost.Editor.Controls.Internal;
internal unsafe sealed partial class ComponentDataView : Control
{
private StackPanel? _contentContainer;
private readonly World? _world;
private readonly Entity _entity = Entity.Invalid;
private readonly Type? _componentType;
private EventHandler<object>? _updateHandler;
private IComponentEditor? _customEditor;
private PropertyField[]? _propertyFields;
public string HeaderText
{
get => (string)GetValue(HeaderTextProperty);
set => SetValue(HeaderTextProperty, value);
}
public static readonly DependencyProperty HeaderTextProperty =
DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ComponentDataView), new PropertyMetadata(string.Empty));
internal ComponentDataView()
{
DefaultStyleKey = typeof(ComponentDataView);
Unloaded += (s, e) =>
{
CompositionTarget.Rendering -= _updateHandler;
_contentContainer = null;
_customEditor = null;
_propertyFields = null;
};
}
public ComponentDataView(string header, World world, Entity entity, Type componentType) : this()
{
HeaderText = header;
_world = world;
_entity = entity;
_componentType = componentType;
}
protected override void OnApplyTemplate()
{
_contentContainer = (StackPanel)GetTemplateChild("ContentContainer");
base.OnApplyTemplate();
ReBuild();
}
private void ReflectionUpdate(object? sender, object e)
{
if (_propertyFields == null)
{
return;
}
foreach (var propertyField in _propertyFields)
{
propertyField.UpdateValue();
}
}
private void CustomEditorUpdate(object? sender, object e)
{
_customEditor!.Update(new ComponentObject(_world!, _entity));
}
public void ReBuild()
{
if (_contentContainer == null)
{
return;
}
_contentContainer.Children.Clear();
if (_world == null || _componentType == null || _entity == Entity.Invalid)
{
return;
}
var componentObject = new ComponentObject(_world, _entity);
var editorType = TypeCache.GetTypes().FirstOrDefault(t =>
typeof(IComponentEditor).IsAssignableFrom(t) &&
t.GetCustomAttribute<CustomEditorAttribute>()?.TargetType.IsAssignableFrom(_componentType) == true);
if (editorType != null)
{
_customEditor = (IComponentEditor)Activator.CreateInstance(editorType)!;
_customEditor.Create(componentObject, _contentContainer);
}
else
{
var fields = _componentType.GetFields(StaticResource.componentPropertyBindingFlags);
_propertyFields = new PropertyField[fields.Length];
for (var i = 0; i < fields.Length; i++)
{
var field = fields[i];
var component = _world.ComponentStorage.ComponentPools[_componentType.TypeHandle.Value].Get(_entity);
var propertyField = PropertyField.Create(field.Name, field, component);
_propertyFields[i] = propertyField;
_contentContainer.Children.Add(propertyField);
}
}
_updateHandler = _customEditor == null ? ReflectionUpdate : CustomEditorUpdate;
CompositionTarget.Rendering += _updateHandler;
}
}