新Head
This commit is contained in:
70
Assets/000_assets/shader/New Material.mat
Normal file
70
Assets/000_assets/shader/New Material.mat
Normal file
@@ -0,0 +1,70 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: New Material
|
||||
m_Shader: {fileID: 4800000, guid: 4aa0ba8da2b8f5b4ca69696b5c13144c, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses:
|
||||
- MOTIONVECTORS
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- unity_Lightmaps:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_LightmapsInd:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- unity_ShadowMasks:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _AlphaCutoff: 0.5
|
||||
- _Opacity: 1
|
||||
- _count: 8
|
||||
- _cube_radius: 0.033
|
||||
- _cube_softness: 0
|
||||
- _cube_width: 0.05
|
||||
- _gap_softness: 0
|
||||
- _gapsize: 0.5
|
||||
- _ring_radius: 0.5
|
||||
- _ring_rotation: 0
|
||||
- _ring_softness: 0
|
||||
- _ring_width: 0.02
|
||||
m_Colors:
|
||||
- _EmissionColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ImageColor: {r: 1, g: 1, b: 1, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &2669937578497038573
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 11
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
|
||||
version: 10
|
||||
8
Assets/000_assets/shader/New Material.mat.meta
Normal file
8
Assets/000_assets/shader/New Material.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b546731ae38d4ae47bd9a1cdd80ea2f1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1016
Assets/000_assets/shader/hit_point.shader
Normal file
1016
Assets/000_assets/shader/hit_point.shader
Normal file
File diff suppressed because it is too large
Load Diff
9
Assets/000_assets/shader/hit_point.shader.meta
Normal file
9
Assets/000_assets/shader/hit_point.shader.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aa0ba8da2b8f5b4ca69696b5c13144c
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38766
Assets/FR2_Cache.asset
38766
Assets/FR2_Cache.asset
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7986888078867694945}
|
||||
- component: {fileID: 1245899045477576615}
|
||||
- component: {fileID: 2422713327444875072}
|
||||
m_Layer: 5
|
||||
m_Name: DynamicUISubcontainer
|
||||
@@ -37,30 +36,6 @@ RectTransform:
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 650, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1245899045477576615
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5517159431924024882}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8a8695521f0d02e499659fee002a26c2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Padding:
|
||||
m_Left: 15
|
||||
m_Right: 15
|
||||
m_Top: 15
|
||||
m_Bottom: 15
|
||||
m_ChildAlignment: 0
|
||||
m_StartCorner: 0
|
||||
m_StartAxis: 0
|
||||
m_CellSize: {x: 200, y: 100}
|
||||
m_Spacing: {x: 10, y: 10}
|
||||
m_Constraint: 0
|
||||
m_ConstraintCount: 2
|
||||
--- !u!114 &2422713327444875072
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -74,6 +49,7 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
parentContainer: {fileID: 0}
|
||||
gridLayoutGroup: {fileID: 1245899045477576615}
|
||||
horizontalLayoutGroup: {fileID: 0}
|
||||
rect: {fileID: 7986888078867694945}
|
||||
dynamicUIElements: []
|
||||
rowHeight: 100
|
||||
|
||||
@@ -103,20 +103,23 @@ MonoBehaviour:
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
@@ -185,8 +188,8 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
title: {fileID: 4146383444293307128}
|
||||
canvasGroup: {fileID: 0}
|
||||
parameterName:
|
||||
isAlwaysUpdated: 0
|
||||
text: {fileID: 1511802765271541473}
|
||||
--- !u!1 &4303436613740383453
|
||||
GameObject:
|
||||
@@ -291,20 +294,23 @@ MonoBehaviour:
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_enableWordWrapping: 1
|
||||
m_TextWrappingMode: 0
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 1
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Ichni.Editor.Commands
|
||||
{
|
||||
if (target == null) return;
|
||||
ReflectionHelper.SetDeepValue(target, path, newValue);
|
||||
target.Refresh();
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
@@ -38,9 +39,8 @@ namespace Ichni.Editor.Commands
|
||||
if (target == null) return;
|
||||
|
||||
ReflectionHelper.SetDeepValue(target, path, oldValue);
|
||||
target.Refresh();
|
||||
|
||||
|
||||
target.Refresh();
|
||||
RefreshInspectorIfMatched();
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
@@ -49,8 +49,7 @@ namespace Ichni.Editor.Commands
|
||||
|
||||
ReflectionHelper.SetDeepValue(target, path, newValue);
|
||||
target.Refresh();
|
||||
|
||||
|
||||
RefreshInspectorIfMatched();
|
||||
}
|
||||
|
||||
public bool TryMerge(ICommand other)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea823e8c44a0ca842a3b0e59390994de
|
||||
guid: ef107ab630341ed4083145b5a21db705
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
163
Assets/Scripts/DynamicUI/Core/DrawerRegistry.cs
Normal file
163
Assets/Scripts/DynamicUI/Core/DrawerRegistry.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型→绘制器注册表。集中管理 Prefab 引用和 Type→IPropertyDrawer 映射。
|
||||
/// 替代分散在 IHaveInspection 各 Generate 方法中的 basePrefabs 直接访问。
|
||||
/// 使用惰性单例,首次访问时自动注册所有内置 Drawer。
|
||||
/// </summary>
|
||||
public class DrawerRegistry
|
||||
{
|
||||
private static DrawerRegistry _instance;
|
||||
|
||||
/// <summary> 全局单例 </summary>
|
||||
public static DrawerRegistry Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new DrawerRegistry();
|
||||
_instance.RegisterBuiltInDrawers();
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
// 按属性类型注册的 Drawer (优先级最高)
|
||||
private readonly Dictionary<Type, IPropertyDrawer> _attributeDrawers = new Dictionary<Type, IPropertyDrawer>();
|
||||
|
||||
// 按字段类型注册的 Drawer
|
||||
private readonly Dictionary<Type, IPropertyDrawer> _typeDrawers = new Dictionary<Type, IPropertyDrawer>();
|
||||
|
||||
// 特殊 Drawer (Button, HintText 等不绑定字段类型的)
|
||||
private readonly Dictionary<string, IPropertyDrawer> _namedDrawers = new Dictionary<string, IPropertyDrawer>();
|
||||
|
||||
// Fallback Drawer
|
||||
private IPropertyDrawer _fallbackDrawer;
|
||||
|
||||
/// <summary> Prefab 引用桥接到 BasePrefabsCollection </summary>
|
||||
private BasePrefabsCollection Prefabs => EditorManager.instance.basePrefabs;
|
||||
|
||||
/// <summary> 注册字段类型→Drawer 映射 </summary>
|
||||
public void RegisterDrawer(Type fieldType, IPropertyDrawer drawer)
|
||||
{
|
||||
_typeDrawers[fieldType] = drawer;
|
||||
}
|
||||
|
||||
/// <summary> 注册属性类型→Drawer 映射(属性特化优先于字段类型) </summary>
|
||||
public void RegisterAttributeDrawer<TAttr>(IPropertyDrawer drawer) where TAttr : Attribute
|
||||
{
|
||||
_attributeDrawers[typeof(TAttr)] = drawer;
|
||||
}
|
||||
|
||||
/// <summary> 注册命名 Drawer(用于 Button、HintText 等非类型绑定的控件) </summary>
|
||||
public void RegisterNamedDrawer(string name, IPropertyDrawer drawer)
|
||||
{
|
||||
_namedDrawers[name] = drawer;
|
||||
}
|
||||
|
||||
/// <summary> 设置 Fallback Drawer(类型未注册时使用) </summary>
|
||||
public void SetFallbackDrawer(IPropertyDrawer drawer)
|
||||
{
|
||||
_fallbackDrawer = drawer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取适用的 Drawer。查找优先级:
|
||||
/// 1. 属性注册(如 [InspectorSlider] → SliderDrawer)
|
||||
/// 2. 类型注册(如 bool → ToggleDrawer)
|
||||
/// 3. Enum 基类型检测
|
||||
/// 4. Fallback (InputFieldDrawer)
|
||||
/// </summary>
|
||||
public IPropertyDrawer GetDrawer(Type fieldType, Attribute[] attributes = null)
|
||||
{
|
||||
// 1. 属性特化优先
|
||||
if (attributes != null)
|
||||
{
|
||||
foreach (var attr in attributes)
|
||||
{
|
||||
if (_attributeDrawers.TryGetValue(attr.GetType(), out var attrDrawer))
|
||||
return attrDrawer;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 精确类型匹配
|
||||
if (fieldType != null && _typeDrawers.TryGetValue(fieldType, out var typeDrawer))
|
||||
return typeDrawer;
|
||||
|
||||
// 3. Enum 基类型检测
|
||||
if (fieldType != null && fieldType.IsEnum && _typeDrawers.TryGetValue(typeof(Enum), out var enumDrawer))
|
||||
return enumDrawer;
|
||||
|
||||
// 4. Fallback
|
||||
return _fallbackDrawer;
|
||||
}
|
||||
|
||||
/// <summary> 获取命名 Drawer </summary>
|
||||
public IPropertyDrawer GetNamedDrawer(string name)
|
||||
{
|
||||
_namedDrawers.TryGetValue(name, out var drawer);
|
||||
return drawer;
|
||||
}
|
||||
|
||||
/// <summary> 获取 DynamicUI Element Prefab </summary>
|
||||
public GameObject GetPrefab(string elementType)
|
||||
{
|
||||
return elementType switch
|
||||
{
|
||||
"button" => Prefabs.button,
|
||||
"toggle" => Prefabs.toggle,
|
||||
"inputField" => Prefabs.inputField,
|
||||
"slider" => Prefabs.slider,
|
||||
"vector2InputField" => Prefabs.vector2InputField,
|
||||
"vector3InputField" => Prefabs.vector3InputField,
|
||||
"enumDropdown" => Prefabs.enumDropdown,
|
||||
"stringListDropdown" => Prefabs.stringListDropdown,
|
||||
"baseColorPicker" => Prefabs.baseColorPicker,
|
||||
"emissionColorPicker" => Prefabs.emissionColorPicker,
|
||||
"hintText" => Prefabs.hintText,
|
||||
"parameterText" => Prefabs.parameterText,
|
||||
"hsvDrawer" => Prefabs.hsvDrawer,
|
||||
"container" => Prefabs.dynamicUIContainer,
|
||||
"subcontainer" => Prefabs.dynamicUISubcontainer,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册所有内置 Drawer,覆盖全部基本字段类型和特化属性。
|
||||
/// </summary>
|
||||
private void RegisterBuiltInDrawers()
|
||||
{
|
||||
// 基本类型 Drawer
|
||||
var inputFieldDrawer = new InputFieldDrawer();
|
||||
RegisterDrawer(typeof(float), inputFieldDrawer);
|
||||
RegisterDrawer(typeof(int), inputFieldDrawer);
|
||||
RegisterDrawer(typeof(string), inputFieldDrawer);
|
||||
SetFallbackDrawer(inputFieldDrawer);
|
||||
|
||||
RegisterDrawer(typeof(bool), new ToggleDrawer());
|
||||
RegisterDrawer(typeof(System.Enum), new EnumDropdownDrawer());
|
||||
RegisterDrawer(typeof(Vector2), new Vector2FieldDrawer());
|
||||
RegisterDrawer(typeof(Vector3), new Vector3FieldDrawer());
|
||||
RegisterDrawer(typeof(Color), new BaseColorPickerDrawer());
|
||||
|
||||
// 属性特化 Drawer
|
||||
RegisterAttributeDrawer<InspectorSliderAttribute>(new SliderDrawer());
|
||||
RegisterAttributeDrawer<InspectorEmissionColorAttribute>(new EmissionColorPickerDrawer());
|
||||
|
||||
// 命名 Drawer(非类型绑定的控件)
|
||||
RegisterNamedDrawer("button", new ButtonDrawer());
|
||||
RegisterNamedDrawer("hintText", new HintTextDrawer());
|
||||
RegisterNamedDrawer("parameterText", new ParameterTextDrawer());
|
||||
RegisterNamedDrawer("slider", new SliderDrawer());
|
||||
RegisterNamedDrawer("stringListDropdown", new StringListDropdownDrawer());
|
||||
RegisterNamedDrawer("emissionColorPicker", new EmissionColorPickerDrawer());
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Core/DrawerRegistry.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Core/DrawerRegistry.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b796d9d7294bb5248a040f9e7dc8be8b
|
||||
27
Assets/Scripts/DynamicUI/Core/ElementRef.cs
Normal file
27
Assets/Scripts/DynamicUI/Core/ElementRef.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 延迟引用容器 —— 在 Build() 时由 InspectorBuilder 填充。
|
||||
/// 用于在 Button 回调中访问其他控件(如 UnboundInputField 的值)。
|
||||
///
|
||||
/// 用法:
|
||||
/// <code>
|
||||
/// var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
/// InspectorBuilder.For(this)
|
||||
/// .Section("Search")
|
||||
/// .UnboundInputField("Name").WithRef(nameRef)
|
||||
/// .Button("Find", () => {
|
||||
/// string name = nameRef.Value?.GetValue<string>();
|
||||
/// })
|
||||
/// .Build();
|
||||
/// </code>
|
||||
/// </summary>
|
||||
public class ElementRef<T> where T : DynamicUIElement
|
||||
{
|
||||
/// <summary> 构建后填充的控件实例,Build() 之前为 null </summary>
|
||||
public T Value { get; internal set; }
|
||||
|
||||
/// <summary> 隐式转换,方便直接当 T 使用 </summary>
|
||||
public static implicit operator T(ElementRef<T> r) => r?.Value;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Core/ElementRef.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Core/ElementRef.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2de2ed51f60dceb469874524fb69bd28
|
||||
118
Assets/Scripts/DynamicUI/Core/IPropertyDrawer.cs
Normal file
118
Assets/Scripts/DynamicUI/Core/IPropertyDrawer.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 可插拔属性绘制器接口。每种字段类型(bool, float, Color 等)
|
||||
/// 对应一个 Drawer 实现,负责创建和配置对应类型的 DynamicUIElement。
|
||||
/// </summary>
|
||||
public interface IPropertyDrawer
|
||||
{
|
||||
/// <summary> 默认占据的列数 (1-3),1 = 1/3 行宽 </summary>
|
||||
int DefaultSpan { get; }
|
||||
|
||||
/// <summary> 默认高度 (px) </summary>
|
||||
float DefaultHeight { get; }
|
||||
|
||||
/// <summary> 创建并初始化一个 DynamicUIElement,挂载到 parent 下 </summary>
|
||||
DynamicUIElement Draw(DrawContext ctx);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绘制上下文,传递给 IPropertyDrawer.Draw() 的所有必要信息。
|
||||
/// 由 InspectorBuilder 在 Build() 时构造。
|
||||
/// </summary>
|
||||
public struct DrawContext
|
||||
{
|
||||
/// <summary> 绑定的目标元素 </summary>
|
||||
public IBaseElement Target;
|
||||
|
||||
/// <summary> 反射路径(ReflectionHelper 使用的字段名) </summary>
|
||||
public string FieldName;
|
||||
|
||||
/// <summary> 显示标签 </summary>
|
||||
public string Label;
|
||||
|
||||
/// <summary> 父容器(Row 的 RectTransform) </summary>
|
||||
public Transform Parent;
|
||||
|
||||
/// <summary> Drawer 注册表,用于获取 Prefab 引用 </summary>
|
||||
public DrawerRegistry Registry;
|
||||
|
||||
/// <summary> 目标 Inspector 窗口(用于 Mark 和 MarkedElements 注册) </summary>
|
||||
public IHaveInspection Inspection;
|
||||
|
||||
// ──────── 可选配置(由 Builder 链式方法设置)────────
|
||||
|
||||
/// <summary> 覆盖默认 Span </summary>
|
||||
public int? OverrideSpan;
|
||||
|
||||
/// <summary> 覆盖默认高度 </summary>
|
||||
public float? OverrideHeight;
|
||||
|
||||
/// <summary> 是否启用自动更新 </summary>
|
||||
public bool AutoUpdate;
|
||||
|
||||
/// <summary> 是否只读 </summary>
|
||||
public bool ReadOnly;
|
||||
|
||||
/// <summary> 值变更时的回调 </summary>
|
||||
public Action OnChangedCallback;
|
||||
|
||||
/// <summary> 控件启用条件(返回 false 时禁用交互) </summary>
|
||||
public Func<bool> EnabledCondition;
|
||||
|
||||
/// <summary> Mark 标记键 </summary>
|
||||
public string MarkKey;
|
||||
|
||||
// ──────── Slider 专用 ────────
|
||||
public float SliderMin;
|
||||
public float SliderMax;
|
||||
public bool SliderWholeNumbers;
|
||||
|
||||
// ──────── EmissionColor 专用 ────────
|
||||
public string EmissionEnabledName;
|
||||
public string EmissionIntensityName;
|
||||
|
||||
// ──────── Button 专用 ────────
|
||||
public Action ButtonAction;
|
||||
|
||||
// ──────── HintText 专用 ────────
|
||||
public string StaticText;
|
||||
public Func<string> DynamicText;
|
||||
|
||||
// ──────── Dropdown 专用 ────────
|
||||
public Type EnumType;
|
||||
public List<string> StringListOptions;
|
||||
|
||||
// ──────── Unbound 控件 ────────
|
||||
|
||||
/// <summary> 无绑定控件类型 (None = 正常绑定控件) </summary>
|
||||
public UnboundKind Unbound;
|
||||
|
||||
/// <summary> 无绑定 InputField 的默认文本 </summary>
|
||||
public string DefaultText;
|
||||
|
||||
/// <summary> 无绑定 Slider 的默认值 </summary>
|
||||
public float DefaultFloat;
|
||||
|
||||
/// <summary> 无绑定 Vector3Field 的默认值 </summary>
|
||||
public Vector3 DefaultVector3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无绑定控件类型枚举。
|
||||
/// None 表示正常的数据绑定控件;其他值表示不绑定任何字段的独立控件。
|
||||
/// </summary>
|
||||
public enum UnboundKind
|
||||
{
|
||||
None = 0,
|
||||
InputField,
|
||||
Toggle,
|
||||
Slider,
|
||||
Vector3Field,
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Core/IPropertyDrawer.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Core/IPropertyDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cefee972a8f49184aaff2f2559b67fcf
|
||||
147
Assets/Scripts/DynamicUI/Core/InspectorAttributes.cs
Normal file
147
Assets/Scripts/DynamicUI/Core/InspectorAttributes.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 字段/属性标注 —— 驱动 InspectorBuilder.AutoBuild() 自动生成 UI 控件。
|
||||
/// 替代旧版 DynamicUIAttribute,新增 GroupOrder 和 Order 排序支持。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class InspectorFieldAttribute : Attribute
|
||||
{
|
||||
/// <summary> 显示名称,为空时使用成员名 </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary> 所属 Section 标题 </summary>
|
||||
public string Group { get; set; }
|
||||
|
||||
/// <summary> Section 排序权重(与 InspectorBuilder.Section 的 sectionOrder 统一排序,升序) </summary>
|
||||
public int GroupOrder { get; set; }
|
||||
|
||||
/// <summary> Section 内元素排序权重(升序,同 order 按声明顺序 stable sort) </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排版格子要求。一行最大宽度分为 3 份。
|
||||
/// 填 1 代表需占 1/3。填 3 代表全宽占满整行。
|
||||
/// 填 0 由内置工厂根据数据类型自动识别。
|
||||
/// </summary>
|
||||
public int Span { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 垂直占位高度 (px)。填 0 由系统按类型智能推断。
|
||||
/// </summary>
|
||||
public float Height { get; set; }
|
||||
|
||||
/// <summary> 是否自动更新(绑定 IHaveAutoUpdate) </summary>
|
||||
public bool AutoUpdate { get; set; }
|
||||
|
||||
/// <summary> 只读模式(生成 HintText 替代可编辑控件) </summary>
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
public InspectorFieldAttribute(
|
||||
string name = "",
|
||||
string group = "Default",
|
||||
int groupOrder = 0,
|
||||
int order = 0,
|
||||
int span = 0,
|
||||
float height = 0f,
|
||||
bool autoUpdate = false,
|
||||
bool readOnly = false)
|
||||
{
|
||||
Name = name;
|
||||
Group = group;
|
||||
GroupOrder = groupOrder;
|
||||
Order = order;
|
||||
Span = span;
|
||||
Height = height;
|
||||
AutoUpdate = autoUpdate;
|
||||
ReadOnly = readOnly;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slider 控件标注,适用于 float/int 类型字段。
|
||||
/// 替代旧版 DynamicUISliderAttribute。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class InspectorSliderAttribute : InspectorFieldAttribute
|
||||
{
|
||||
public float Min { get; set; }
|
||||
public float Max { get; set; }
|
||||
public bool WholeNumbers { get; set; }
|
||||
|
||||
public InspectorSliderAttribute(
|
||||
string name = "",
|
||||
string group = "Default",
|
||||
float min = 0f,
|
||||
float max = 1f,
|
||||
bool wholeNumbers = false,
|
||||
int groupOrder = 0,
|
||||
int order = 0,
|
||||
int span = 0,
|
||||
float height = 0f,
|
||||
bool autoUpdate = false,
|
||||
bool readOnly = false)
|
||||
: base(name, group, groupOrder, order, span, height, autoUpdate, readOnly)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
WholeNumbers = wholeNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EmissionColor 拾色器标注,支持 HDR 及独立 Emission 强度/开关通道。
|
||||
/// 替代旧版 DynamicUIEmissionColorAttribute。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class InspectorEmissionColorAttribute : InspectorFieldAttribute
|
||||
{
|
||||
/// <summary> Emission 开关字段名,"NULL" 表示强制启用 </summary>
|
||||
public string EmissionEnabledName { get; set; }
|
||||
|
||||
/// <summary> Emission 强度字段名,"NULL" 表示使用颜色 Alpha 通道 </summary>
|
||||
public string EmissionIntensityName { get; set; }
|
||||
|
||||
public InspectorEmissionColorAttribute(
|
||||
string name,
|
||||
string enabledName = "NULL",
|
||||
string intensityName = "NULL",
|
||||
string group = "Default",
|
||||
int groupOrder = 0,
|
||||
int order = 0,
|
||||
int span = 3,
|
||||
float height = 0f)
|
||||
: base(name, group, groupOrder, order, span, height)
|
||||
{
|
||||
EmissionEnabledName = enabledName;
|
||||
EmissionIntensityName = intensityName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按钮标注,挂载在无参 Method 上。
|
||||
/// 替代旧版 DynamicUIButtonAttribute。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class InspectorButtonAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Group { get; set; }
|
||||
public int GroupOrder { get; set; }
|
||||
public int Order { get; set; }
|
||||
|
||||
public InspectorButtonAttribute(
|
||||
string name = "",
|
||||
string group = "Default",
|
||||
int groupOrder = 0,
|
||||
int order = 0)
|
||||
{
|
||||
Name = name;
|
||||
Group = group;
|
||||
GroupOrder = groupOrder;
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be7c441b9cc629e4287d879fd13a700f
|
||||
1203
Assets/Scripts/DynamicUI/Core/InspectorBuilder.cs
Normal file
1203
Assets/Scripts/DynamicUI/Core/InspectorBuilder.cs
Normal file
File diff suppressed because it is too large
Load Diff
2
Assets/Scripts/DynamicUI/Core/InspectorBuilder.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Core/InspectorBuilder.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f497f16c91f01db48ab2e21dc67a0f3b
|
||||
181
Assets/Scripts/DynamicUI/Core/LayoutPacker.cs
Normal file
181
Assets/Scripts/DynamicUI/Core/LayoutPacker.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动行打包算法 —— 将元素列表按 Span 和高度层级自动装入行。
|
||||
/// 替代手动调用 GenerateSubcontainer(N) 手动分配列数。
|
||||
/// </summary>
|
||||
public static class LayoutPacker
|
||||
{
|
||||
/// <summary> 每行最大 Span 总量 </summary>
|
||||
public const int MaxSpanPerRow = 3;
|
||||
|
||||
/// <summary> 行总宽度 (px),与 DynamicUI 现有 600px 布局一致 </summary>
|
||||
public const float TotalRowWidth = 600f;
|
||||
|
||||
/// <summary> 默认行高 (px) </summary>
|
||||
public const float DefaultRowHeight = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// 高度层级。同一行内只允许相同层级的元素,
|
||||
/// 避免 100px 的 Toggle 和 280px 的 ColorPicker 混排导致空白浪费。
|
||||
/// </summary>
|
||||
public enum HeightTier
|
||||
{
|
||||
/// <summary> 标准高度 (<= 100px): bool, float, int, string, enum, Vector2, Vector3, Button... </summary>
|
||||
Standard,
|
||||
/// <summary> 中等高度 (<= 280px): BaseColorPicker </summary>
|
||||
Tall,
|
||||
/// <summary> 超高 (> 280px): EmissionColorPicker 等 </summary>
|
||||
ExtraTall
|
||||
}
|
||||
|
||||
/// <summary> 待打包的元素定义 </summary>
|
||||
public struct ElementDef
|
||||
{
|
||||
/// <summary> 占据的列数 (1-3) </summary>
|
||||
public int Span;
|
||||
|
||||
/// <summary> 元素高度 (px) </summary>
|
||||
public float Height;
|
||||
|
||||
/// <summary> 高度层级(由 Height 自动推断) </summary>
|
||||
public HeightTier Tier;
|
||||
|
||||
/// <summary> 排序权重(Section 内排序) </summary>
|
||||
public int Order;
|
||||
|
||||
/// <summary> 稳定排序用的原始插入索引 </summary>
|
||||
public int InsertionIndex;
|
||||
|
||||
/// <summary> 绘制上下文 </summary>
|
||||
public DrawContext Context;
|
||||
|
||||
/// <summary> 对应的绘制器 </summary>
|
||||
public IPropertyDrawer Drawer;
|
||||
}
|
||||
|
||||
/// <summary> 一行的定义 </summary>
|
||||
public struct RowDef
|
||||
{
|
||||
/// <summary> 行内元素 </summary>
|
||||
public List<ElementDef> Elements;
|
||||
|
||||
/// <summary> 行高 = max(行内所有元素的 Height) </summary>
|
||||
public float RowHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将元素列表打包为行列表。
|
||||
/// 约束: 同一行内 Span 总和 <= MaxSpanPerRow,且元素必须属于相同 HeightTier。
|
||||
/// 元素先按 Order 升序 stable sort,再按顺序贪心装箱。
|
||||
/// </summary>
|
||||
public static List<RowDef> Pack(List<ElementDef> elements)
|
||||
{
|
||||
var rows = new List<RowDef>();
|
||||
if (elements == null || elements.Count == 0)
|
||||
return rows;
|
||||
|
||||
// Stable sort: 先按 Order 升序,同 Order 按 InsertionIndex 升序
|
||||
elements.Sort((a, b) =>
|
||||
{
|
||||
int cmp = a.Order.CompareTo(b.Order);
|
||||
return cmp != 0 ? cmp : a.InsertionIndex.CompareTo(b.InsertionIndex);
|
||||
});
|
||||
|
||||
var currentRow = new List<ElementDef>();
|
||||
int currentSpan = 0;
|
||||
HeightTier currentTier = elements[0].Tier;
|
||||
float currentMaxHeight = 0f;
|
||||
|
||||
int currentRowSpan = -1; // 当前行元素的 Span 值(-1 表示尚未确定)
|
||||
|
||||
for (int i = 0; i < elements.Count; i++)
|
||||
{
|
||||
var elem = elements[i];
|
||||
int elemSpan = Mathf.Clamp(elem.Span, 1, MaxSpanPerRow);
|
||||
|
||||
bool spanOverflow = currentSpan + elemSpan > MaxSpanPerRow;
|
||||
bool tierMismatch = currentRow.Count > 0 && elem.Tier != currentTier;
|
||||
// GridLayoutGroup 强制统一 cellSize,同一行内混搭不同 Span 宽度会导致变形
|
||||
bool spanMismatch = currentRow.Count > 0 && elemSpan != currentRowSpan;
|
||||
|
||||
if (spanOverflow || tierMismatch || spanMismatch)
|
||||
{
|
||||
// 当前行已满、高度层级不兼容或 Span 不一致,提交当前行
|
||||
FlushRow(rows, currentRow, currentMaxHeight);
|
||||
currentRow = new List<ElementDef>();
|
||||
currentSpan = 0;
|
||||
currentMaxHeight = 0f;
|
||||
currentTier = elem.Tier;
|
||||
currentRowSpan = -1;
|
||||
}
|
||||
|
||||
currentRow.Add(elem);
|
||||
currentSpan += elemSpan;
|
||||
currentRowSpan = elemSpan;
|
||||
if (elem.Height > currentMaxHeight)
|
||||
currentMaxHeight = elem.Height;
|
||||
}
|
||||
|
||||
// 提交最后一行
|
||||
if (currentRow.Count > 0)
|
||||
{
|
||||
FlushRow(rows, currentRow, currentMaxHeight);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary> 根据高度值推断 HeightTier </summary>
|
||||
public static HeightTier InferTier(float height)
|
||||
{
|
||||
if (height <= DefaultRowHeight)
|
||||
return HeightTier.Standard;
|
||||
if (height <= 280f)
|
||||
return HeightTier.Tall;
|
||||
return HeightTier.ExtraTall;
|
||||
}
|
||||
|
||||
/// <summary> 根据类型推断默认 Span </summary>
|
||||
public static int InferSpan(System.Type fieldType)
|
||||
{
|
||||
if (fieldType == null) return 1;
|
||||
if (fieldType == typeof(bool)) return 1;
|
||||
if (fieldType == typeof(float) || fieldType == typeof(int) || fieldType == typeof(string)) return 1;
|
||||
if (fieldType.IsEnum) return 1;
|
||||
if (fieldType == typeof(Vector2)) return 2;
|
||||
if (fieldType == typeof(Vector3) || fieldType == typeof(Color)) return 3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// <summary> 根据类型推断默认高度 </summary>
|
||||
public static float InferHeight(System.Type fieldType, System.Attribute[] attributes = null)
|
||||
{
|
||||
if (attributes != null)
|
||||
{
|
||||
foreach (var attr in attributes)
|
||||
{
|
||||
if (attr is InspectorEmissionColorAttribute)
|
||||
return 320f;
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldType == typeof(Color))
|
||||
return 280f;
|
||||
|
||||
return DefaultRowHeight;
|
||||
}
|
||||
|
||||
private static void FlushRow(List<RowDef> rows, List<ElementDef> rowElements, float maxHeight)
|
||||
{
|
||||
rows.Add(new RowDef
|
||||
{
|
||||
Elements = rowElements,
|
||||
RowHeight = Mathf.Max(maxHeight, DefaultRowHeight)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Core/LayoutPacker.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Core/LayoutPacker.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4e8a9feff817f194da598f2ef0c357ea
|
||||
8
Assets/Scripts/DynamicUI/Drawers.meta
Normal file
8
Assets/Scripts/DynamicUI/Drawers.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25964ec060be79b4f835e09d9383ad7a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Scripts/DynamicUI/Drawers/BaseColorPickerDrawer.cs
Normal file
37
Assets/Scripts/DynamicUI/Drawers/BaseColorPickerDrawer.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 Color 类型的 Drawer。
|
||||
/// 创建 DynamicUIBaseColorPicker。
|
||||
/// </summary>
|
||||
public class BaseColorPickerDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 3;
|
||||
public float DefaultHeight => 280f;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("baseColorPicker"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIBaseColorPicker>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
DynamicUIElement.DisableNavigation(
|
||||
element.inputFieldBaseR,
|
||||
element.inputFieldBaseG,
|
||||
element.inputFieldBaseB,
|
||||
element.inputFieldBaseA);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f148308680f4a4b47a9d1097376ca1aa
|
||||
40
Assets/Scripts/DynamicUI/Drawers/ButtonDrawer.cs
Normal file
40
Assets/Scripts/DynamicUI/Drawers/ButtonDrawer.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 按钮 Drawer,不绑定数据字段。
|
||||
/// 创建 DynamicUIButton 并绑定 ButtonAction。
|
||||
/// </summary>
|
||||
public class ButtonDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("button"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIButton>();
|
||||
|
||||
element.SetText(ctx.Label);
|
||||
element.Initialize(ctx.Target, ctx.Label, string.Empty);
|
||||
|
||||
if (ctx.ButtonAction != null)
|
||||
{
|
||||
UnityAction action = () => ctx.ButtonAction();
|
||||
element.ApplyFunction(action);
|
||||
}
|
||||
|
||||
DynamicUIElement.DisableNavigation(element.button);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Drawers/ButtonDrawer.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Drawers/ButtonDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23d17d2a4ce34f84a84f140f213d166c
|
||||
@@ -0,0 +1,40 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理带 [InspectorEmissionColor] 属性的 Color 类型的 Drawer。
|
||||
/// 创建 DynamicUIEmissionColorPicker,支持 Emission 开关和强度控制。
|
||||
/// </summary>
|
||||
public class EmissionColorPickerDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 3;
|
||||
public float DefaultHeight => 320f;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("emissionColorPicker"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIEmissionColorPicker>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label,
|
||||
ctx.EmissionEnabledName ?? "NULL",
|
||||
ctx.FieldName,
|
||||
ctx.EmissionIntensityName ?? "NULL");
|
||||
|
||||
DynamicUIElement.DisableNavigation(
|
||||
element.inputFieldEmissionR,
|
||||
element.inputFieldEmissionG,
|
||||
element.inputFieldEmissionB,
|
||||
element.inputFieldEmissionI);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 444ef9b226757004f9290d1ea11d2c60
|
||||
49
Assets/Scripts/DynamicUI/Drawers/EnumDropdownDrawer.cs
Normal file
49
Assets/Scripts/DynamicUI/Drawers/EnumDropdownDrawer.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理所有 Enum 类型的 Drawer。
|
||||
/// 通过反射获取字段的枚举类型,创建 DynamicUIEnumDropdown。
|
||||
/// </summary>
|
||||
public class EnumDropdownDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("enumDropdown"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIEnumDropdown>();
|
||||
|
||||
// 获取枚举类型:优先使用 DrawContext 中的 EnumType,fallback 到反射
|
||||
Type enumType = ctx.EnumType;
|
||||
if (enumType == null && ctx.Target != null && !string.IsNullOrEmpty(ctx.FieldName))
|
||||
{
|
||||
var field = ctx.Target.GetType().GetField(ctx.FieldName);
|
||||
if (field != null) enumType = field.FieldType;
|
||||
else
|
||||
{
|
||||
var prop = ctx.Target.GetType().GetProperty(ctx.FieldName);
|
||||
if (prop != null) enumType = prop.PropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
if (enumType != null)
|
||||
{
|
||||
element.SetUpEnum(enumType);
|
||||
}
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13456a684c2325341a1010f04d0dabb5
|
||||
38
Assets/Scripts/DynamicUI/Drawers/HintTextDrawer.cs
Normal file
38
Assets/Scripts/DynamicUI/Drawers/HintTextDrawer.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 提示文本 Drawer,支持静态文本和 Func<string> 动态文本。
|
||||
/// 创建 DynamicUIHintText。
|
||||
/// </summary>
|
||||
public class HintTextDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("hintText"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIHintText>();
|
||||
|
||||
element.Initialize(ctx.Target, string.Empty, string.Empty);
|
||||
|
||||
if (ctx.DynamicText != null)
|
||||
{
|
||||
element.SetUpdatingContent(ctx.DynamicText);
|
||||
}
|
||||
else if (ctx.StaticText != null)
|
||||
{
|
||||
element.SetContent(ctx.StaticText);
|
||||
}
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Drawers/HintTextDrawer.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Drawers/HintTextDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6437a7c7bdd1fe748b37bb0ebda0abd1
|
||||
42
Assets/Scripts/DynamicUI/Drawers/InputFieldDrawer.cs
Normal file
42
Assets/Scripts/DynamicUI/Drawers/InputFieldDrawer.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 float, int, string 类型的 Drawer。
|
||||
/// 创建 DynamicUIInputField 并绑定反射路径。
|
||||
/// </summary>
|
||||
public class InputFieldDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("inputField"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIInputField>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
DynamicUIElement.DisableNavigation(element.inputField);
|
||||
|
||||
if (ctx.AutoUpdate && element is IHaveAutoUpdate autoUpdate)
|
||||
{
|
||||
autoUpdate.SetAutoUpdate(true);
|
||||
}
|
||||
|
||||
if (ctx.ReadOnly)
|
||||
{
|
||||
element.inputField.interactable = false;
|
||||
}
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00072d6a1502bc74d8b7d116cc648bd1
|
||||
35
Assets/Scripts/DynamicUI/Drawers/ParameterTextDrawer.cs
Normal file
35
Assets/Scripts/DynamicUI/Drawers/ParameterTextDrawer.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数文本 Drawer,绑定字段并显示只读文本,支持自动更新。
|
||||
/// 创建 DynamicUIParameterText。
|
||||
/// </summary>
|
||||
public class ParameterTextDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("parameterText"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIParameterText>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
if (ctx.AutoUpdate)
|
||||
{
|
||||
element.SetAutoUpdate(true);
|
||||
}
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9545528a874aff49a39469a79e1860c
|
||||
33
Assets/Scripts/DynamicUI/Drawers/SliderDrawer.cs
Normal file
33
Assets/Scripts/DynamicUI/Drawers/SliderDrawer.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理带 [InspectorSlider] 属性的 float/int 类型的 Drawer。
|
||||
/// 创建 DynamicUISlider 并配置范围参数。
|
||||
/// </summary>
|
||||
public class SliderDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 3;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("slider"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUISlider>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName,
|
||||
ctx.SliderMin, ctx.SliderMax, ctx.SliderWholeNumbers);
|
||||
DynamicUIElement.DisableNavigation(element.slider);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Drawers/SliderDrawer.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Drawers/SliderDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8740b15baf2fd0147a93e04b4fd41051
|
||||
35
Assets/Scripts/DynamicUI/Drawers/StringListDropdownDrawer.cs
Normal file
35
Assets/Scripts/DynamicUI/Drawers/StringListDropdownDrawer.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 List<string> 选择的 Drawer。
|
||||
/// 创建 DynamicUIStringListDropdown 并配置选项列表。
|
||||
/// </summary>
|
||||
public class StringListDropdownDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("stringListDropdown"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIStringListDropdown>();
|
||||
|
||||
if (ctx.StringListOptions != null)
|
||||
{
|
||||
element.SetUpStringList(ctx.StringListOptions);
|
||||
}
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9f1b1ee81941b94cbb465da262713bf
|
||||
32
Assets/Scripts/DynamicUI/Drawers/ToggleDrawer.cs
Normal file
32
Assets/Scripts/DynamicUI/Drawers/ToggleDrawer.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 bool 类型的 Drawer。
|
||||
/// 创建 DynamicUIToggle。
|
||||
/// </summary>
|
||||
public class ToggleDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 1;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("toggle"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIToggle>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
DynamicUIElement.DisableNavigation(element.toggle);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/DynamicUI/Drawers/ToggleDrawer.cs.meta
Normal file
2
Assets/Scripts/DynamicUI/Drawers/ToggleDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86988bf7af4e8864094e9fc687e93d29
|
||||
38
Assets/Scripts/DynamicUI/Drawers/Vector2FieldDrawer.cs
Normal file
38
Assets/Scripts/DynamicUI/Drawers/Vector2FieldDrawer.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 Vector2 类型的 Drawer。
|
||||
/// 创建 DynamicUIVector2InputField。
|
||||
/// </summary>
|
||||
public class Vector2FieldDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 2;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("vector2InputField"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIVector2InputField>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
if (ctx.AutoUpdate)
|
||||
{
|
||||
element.SetAutoUpdate(true);
|
||||
}
|
||||
|
||||
DynamicUIElement.DisableNavigation(element.inputFieldX, element.inputFieldY);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77e741bd7c95a8d4690052986898525e
|
||||
38
Assets/Scripts/DynamicUI/Drawers/Vector3FieldDrawer.cs
Normal file
38
Assets/Scripts/DynamicUI/Drawers/Vector3FieldDrawer.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Ichni.RhythmGame;
|
||||
using Lean.Pool;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理 Vector3 类型的 Drawer。
|
||||
/// 创建 DynamicUIVector3InputField。
|
||||
/// </summary>
|
||||
public class Vector3FieldDrawer : IPropertyDrawer
|
||||
{
|
||||
public int DefaultSpan => 3;
|
||||
public float DefaultHeight => LayoutPacker.DefaultRowHeight;
|
||||
|
||||
public DynamicUIElement Draw(DrawContext ctx)
|
||||
{
|
||||
var go = LeanPool.Spawn(ctx.Registry.GetPrefab("vector3InputField"), ctx.Parent);
|
||||
var element = go.GetComponent<DynamicUIVector3InputField>();
|
||||
|
||||
element.Initialize(ctx.Target, ctx.Label, ctx.FieldName);
|
||||
|
||||
if (ctx.AutoUpdate)
|
||||
{
|
||||
element.SetAutoUpdate(true);
|
||||
}
|
||||
|
||||
DynamicUIElement.DisableNavigation(element.inputFieldX, element.inputFieldY, element.inputFieldZ);
|
||||
|
||||
int span = ctx.OverrideSpan ?? DefaultSpan;
|
||||
float height = ctx.OverrideHeight ?? DefaultHeight;
|
||||
element.SetLayoutSize(span * LayoutPacker.TotalRowWidth / LayoutPacker.MaxSpanPerRow, height);
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09da90190e75fd14886f20c784b4bc6f
|
||||
@@ -74,7 +74,6 @@ namespace Ichni.Editor
|
||||
float.Parse(inputFieldBaseB.text), float.Parse(inputFieldBaseA.text));
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, newValue));
|
||||
colorPreview.color = newValue;
|
||||
connectedBaseElement.Refresh();
|
||||
// 同步到HSV轮盘
|
||||
if (hsvDrawer != null)
|
||||
{
|
||||
|
||||
@@ -1,80 +1,123 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using DG.Tweening;
|
||||
using Ichni.RhythmGame;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public abstract class DynamicUIElement : MonoBehaviour
|
||||
{
|
||||
Inspector Inspector => EditorManager.instance.uiManager.inspector;
|
||||
|
||||
public TMP_Text title;
|
||||
public CanvasGroup canvasGroup;
|
||||
public IBaseElement connectedBaseElement;
|
||||
|
||||
/// <summary>
|
||||
/// 参数名,通过反射获取饿修改对应变量的值
|
||||
/// </summary>
|
||||
public string parameterName;
|
||||
|
||||
public virtual void Initialize(IBaseElement baseElement, string title, string parameterName)
|
||||
{
|
||||
if (canvasGroup == null) canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
this.connectedBaseElement = baseElement;
|
||||
this.parameterName = parameterName;
|
||||
if (title != string.Empty)
|
||||
{
|
||||
this.title.text = title;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.title.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicUIElement Mark(string mark = "Default", IHaveInspection inspection = null)
|
||||
{
|
||||
inspection ??= Inspector;
|
||||
if (mark == "Default")
|
||||
{
|
||||
mark = title.text;
|
||||
}
|
||||
|
||||
inspection.MarkedElements.TryAdd(mark, this);
|
||||
return this;
|
||||
}
|
||||
public abstract DynamicUIElement AddListenerFunction(UnityAction action);
|
||||
}
|
||||
|
||||
public interface IHaveAutoUpdate
|
||||
{
|
||||
public bool isAutoUpdate { get; set; }
|
||||
public bool isReceiving { get; set; }
|
||||
public void SetAutoUpdate(bool enable);
|
||||
|
||||
public void UpdateContent()
|
||||
{
|
||||
if (isAutoUpdate && isReceiving)
|
||||
{
|
||||
ApplyContent();
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyContent();
|
||||
}
|
||||
public interface IHaveTagLink
|
||||
{
|
||||
public IBaseElement connectedBaseElement { get; set; }
|
||||
|
||||
// public void GetApply()
|
||||
// {
|
||||
// EditorManager.instance.projectInformation.tagManager.SyncTagedElement(connectedBaseElement);
|
||||
// }
|
||||
}
|
||||
}
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using DG.Tweening;
|
||||
using Ichni.RhythmGame;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public abstract class DynamicUIElement : MonoBehaviour
|
||||
{
|
||||
Inspector Inspector => EditorManager.instance.uiManager.inspector;
|
||||
|
||||
public TMP_Text title;
|
||||
public CanvasGroup canvasGroup;
|
||||
public IBaseElement connectedBaseElement;
|
||||
|
||||
/// <summary>
|
||||
/// 参数名,通过反射获取饿修改对应变量的值
|
||||
/// </summary>
|
||||
public string parameterName;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存的 LayoutElement,用于 InspectorBuilder 的 Flexible 布局模式。
|
||||
/// </summary>
|
||||
private LayoutElement _layoutElement;
|
||||
|
||||
public virtual void Initialize(IBaseElement baseElement, string title, string parameterName)
|
||||
{
|
||||
if (canvasGroup == null) canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
||||
this.connectedBaseElement = baseElement;
|
||||
this.parameterName = parameterName;
|
||||
if (title != string.Empty)
|
||||
{
|
||||
this.title.text = title;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.title.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
public DynamicUIElement Mark(string mark = "Default", IHaveInspection inspection = null)
|
||||
{
|
||||
inspection ??= Inspector;
|
||||
if (mark == "Default")
|
||||
{
|
||||
mark = title.text;
|
||||
}
|
||||
|
||||
inspection.MarkedElements.TryAdd(mark, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置此元素在 Flexible 布局中的尺寸。
|
||||
/// 由 InspectorBuilder 或 Drawer 在元素创建后调用。
|
||||
/// </summary>
|
||||
public void SetLayoutSize(float preferredWidth, float preferredHeight)
|
||||
{
|
||||
if (_layoutElement == null)
|
||||
_layoutElement = GetComponent<LayoutElement>();
|
||||
if (_layoutElement == null)
|
||||
_layoutElement = gameObject.AddComponent<LayoutElement>();
|
||||
|
||||
_layoutElement.preferredWidth = preferredWidth;
|
||||
_layoutElement.preferredHeight = preferredHeight;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用指定 Selectable 组件的导航(统一处理,避免各 Generate 方法重复编写)。
|
||||
/// </summary>
|
||||
public static void DisableNavigation(Selectable selectable)
|
||||
{
|
||||
if (selectable != null)
|
||||
selectable.navigation = new Navigation { mode = Navigation.Mode.None };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量禁用多个 Selectable 的导航。
|
||||
/// </summary>
|
||||
public static void DisableNavigation(params Selectable[] selectables)
|
||||
{
|
||||
var nav = new Navigation { mode = Navigation.Mode.None };
|
||||
foreach (var s in selectables)
|
||||
{
|
||||
if (s != null)
|
||||
s.navigation = nav;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract DynamicUIElement AddListenerFunction(UnityAction action);
|
||||
}
|
||||
|
||||
public interface IHaveAutoUpdate
|
||||
{
|
||||
public bool isAutoUpdate { get; set; }
|
||||
public bool isReceiving { get; set; }
|
||||
public void SetAutoUpdate(bool enable);
|
||||
|
||||
public void UpdateContent()
|
||||
{
|
||||
if (isAutoUpdate && isReceiving)
|
||||
{
|
||||
ApplyContent();
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyContent();
|
||||
}
|
||||
public interface IHaveTagLink
|
||||
{
|
||||
public IBaseElement connectedBaseElement { get; set; }
|
||||
|
||||
// public void GetApply()
|
||||
// {
|
||||
// EditorManager.instance.projectInformation.tagManager.SyncTagedElement(connectedBaseElement);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ namespace Ichni.Editor
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, colorParameterName, emissionColor));
|
||||
|
||||
colorPreview.color = emissionColor;
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public void SliderChange(float value)
|
||||
|
||||
@@ -49,7 +49,6 @@ namespace Ichni.Editor
|
||||
private void ApplyParameters(int value)
|
||||
{
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, value));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -113,7 +113,6 @@ namespace Ichni.Editor
|
||||
{
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, value));
|
||||
}
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -156,7 +156,6 @@ namespace Ichni.Editor
|
||||
}
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(
|
||||
new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, convertedValue));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace Ichni.Editor
|
||||
private void ApplyParameters(string value)
|
||||
{
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, value));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -53,7 +53,6 @@ namespace Ichni.Editor
|
||||
private void ApplyParameters(bool value)
|
||||
{
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, value));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -116,7 +116,6 @@ namespace Ichni.Editor
|
||||
{
|
||||
Vector2 newValue = new Vector2(float.Parse(inputFieldX.text), float.Parse(inputFieldY.text));
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, newValue));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -135,7 +135,6 @@ namespace Ichni.Editor
|
||||
{
|
||||
Vector3 newValue = new Vector3(float.Parse(inputFieldX.text), float.Parse(inputFieldY.text), float.Parse(inputFieldZ.text));
|
||||
Ichni.Editor.Commands.CommandManager.ExecuteCommand(new Ichni.Editor.Commands.ChangeValueCommand(connectedBaseElement, parameterName, newValue));
|
||||
connectedBaseElement.Refresh();
|
||||
}
|
||||
|
||||
public override DynamicUIElement AddListenerFunction(UnityAction action)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -9,21 +8,64 @@ namespace Ichni.Editor
|
||||
{
|
||||
Inspector Inspector => EditorManager.instance.uiManager.inspector;
|
||||
public DynamicUIContainer parentContainer;
|
||||
public GridLayoutGroup gridLayoutGroup;
|
||||
public RectTransform rect;
|
||||
public List<DynamicUIElement> dynamicUIElements;
|
||||
|
||||
/// <summary> 当前行高 </summary>
|
||||
[HideInInspector]
|
||||
public float rowHeight = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// 使用 GridLayoutGroup 实现 N 列自动换行布局。
|
||||
/// 当添加的元素数量超过 elementCountPerRow 时,会自动换行到下一行。
|
||||
/// </summary>
|
||||
public void Initialize(DynamicUIContainer parentContainer, int elementCountPerRow, float height = 100)
|
||||
{
|
||||
this.parentContainer = parentContainer;
|
||||
this.gridLayoutGroup.cellSize = new Vector2(600f / elementCountPerRow, height);
|
||||
// 支持对象池复用:避免每次 new List 产生 GC,直接清空
|
||||
if (this.dynamicUIElements == null)
|
||||
this.dynamicUIElements = new List<DynamicUIElement>();
|
||||
this.rowHeight = height;
|
||||
|
||||
int columns = Mathf.Max(1, elementCountPerRow);
|
||||
|
||||
// ── 启用 GridLayoutGroup ──
|
||||
var grid = GetComponent<GridLayoutGroup>();
|
||||
if (grid == null)
|
||||
grid = gameObject.AddComponent<GridLayoutGroup>();
|
||||
|
||||
grid.enabled = true;
|
||||
grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount;
|
||||
grid.constraintCount = columns;
|
||||
grid.childAlignment = TextAnchor.UpperLeft;
|
||||
grid.startCorner = GridLayoutGroup.Corner.UpperLeft;
|
||||
grid.startAxis = GridLayoutGroup.Axis.Horizontal;
|
||||
grid.padding = new RectOffset(10, 10, 0, 0);
|
||||
|
||||
float spacing = 10f;
|
||||
float totalSpacing = (columns - 1) * spacing;
|
||||
float cellWidth = (LayoutPacker.TotalRowWidth - totalSpacing) / columns;
|
||||
grid.cellSize = new Vector2(cellWidth, height);
|
||||
grid.spacing = new Vector2(spacing, spacing);
|
||||
|
||||
// ── LayoutElement: preferredHeight = -1 让 GridLayoutGroup 的 ILayoutElement 接管高度 ──
|
||||
var layoutElement = GetComponent<LayoutElement>();
|
||||
if (layoutElement == null)
|
||||
layoutElement = gameObject.AddComponent<LayoutElement>();
|
||||
layoutElement.preferredHeight = -1;
|
||||
layoutElement.flexibleHeight = -1;
|
||||
|
||||
// ── ContentSizeFitter: 让子容器高度随网格行数动态增长 ──
|
||||
var fitter = GetComponent<ContentSizeFitter>();
|
||||
if (fitter == null)
|
||||
fitter = gameObject.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
fitter.enabled = true;
|
||||
|
||||
if (dynamicUIElements == null)
|
||||
dynamicUIElements = new List<DynamicUIElement>();
|
||||
else
|
||||
this.dynamicUIElements.Clear();
|
||||
dynamicUIElements.Clear();
|
||||
}
|
||||
|
||||
|
||||
public DynamicUISubcontainer Mark(string mark, IHaveInspection inspection = null)
|
||||
{
|
||||
inspection ??= Inspector;
|
||||
@@ -31,4 +73,4 @@ namespace Ichni.Editor
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值或枚举控制参数标签,挂载在 Field 或 Property 上
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class DynamicUIAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属于哪个 Container (比如 "InGame Settings" 或 "Path Node")
|
||||
/// </summary>
|
||||
public string Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排版格子要求。一行最大宽度分为 3 份。
|
||||
/// 填 1 代表需占 1/3。填 3 代表全宽占满整行。
|
||||
/// 若填 0,由内置工厂根据数据类型自动识别(例如 Vector3 与 Color 自动为 3,bool为1 等)。
|
||||
/// </summary>
|
||||
public int Span { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 垂直占位高度。填 0 由系统智能推断(如基础件 100,ColorPicker 240),也可显式填写如 150f 覆盖。
|
||||
/// </summary>
|
||||
public float Height { get; set; }
|
||||
|
||||
public bool AutoUpdate { get; set; }
|
||||
public bool ReadOnly { get; set; }
|
||||
|
||||
public DynamicUIAttribute(string name = "", string group = "Default", int span = 0, float height = 0f, bool autoUpdate = false, bool readOnly = false)
|
||||
{
|
||||
Name = name;
|
||||
Group = group;
|
||||
Span = span;
|
||||
Height = height;
|
||||
AutoUpdate = autoUpdate;
|
||||
ReadOnly = readOnly;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 支持 HDR 以及独立 Emission 强度或开关控制通道的拾色器。
|
||||
/// 若无独立通道字段可置为 "NULL",将自动转为读取并写入至 Target Color 的 Alpha 通道中。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class DynamicUIEmissionColorAttribute : DynamicUIAttribute
|
||||
{
|
||||
public string EmissionEnabledName { get; set; }
|
||||
public string EmissionIntensityName { get; set; }
|
||||
|
||||
public DynamicUIEmissionColorAttribute(string name, string enabledName = "NULL", string intensityName = "NULL", string group = "Default", int span = 3, float height = 0f)
|
||||
: base(name, group, span, height)
|
||||
{
|
||||
EmissionEnabledName = enabledName;
|
||||
EmissionIntensityName = intensityName;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 滑块控制属性,适用于 float/int 类型字段,自动生成带范围限制的 Slider 替代 InputField。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||
public class DynamicUISliderAttribute : DynamicUIAttribute
|
||||
{
|
||||
public float Min { get; set; }
|
||||
public float Max { get; set; }
|
||||
public bool WholeNumbers { get; set; }
|
||||
|
||||
public DynamicUISliderAttribute(string name = "", string group = "Default",
|
||||
float min = 0f, float max = 1f, bool wholeNumbers = false,
|
||||
int span = 0, float height = 0f, bool autoUpdate = false, bool readOnly = false)
|
||||
: base(name, group, span, height, autoUpdate, readOnly)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
WholeNumbers = wholeNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 操作按钮卡片,挂载在没有任何参数的 Method() 方法上
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class DynamicUIButtonAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Group { get; set; }
|
||||
|
||||
public DynamicUIButtonAttribute(string name = "", string group = "Default")
|
||||
{
|
||||
Name = name;
|
||||
Group = group;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a540054c95f48544bd6efcea6b452cc
|
||||
@@ -1,228 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public static class DynamicUIAutoBuilder
|
||||
{
|
||||
// 反射信息快取
|
||||
private class FieldDef
|
||||
{
|
||||
public MemberInfo Member;
|
||||
public DynamicUIAttribute Attr;
|
||||
public Type ValueType;
|
||||
}
|
||||
|
||||
private class MethodDef
|
||||
{
|
||||
public MethodInfo Method;
|
||||
public DynamicUIButtonAttribute Attr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接管任何 IBaseElement 的 UI 生成作业
|
||||
/// </summary>
|
||||
public static void AutoBuild(IBaseElement element, IHaveInspection inspector)
|
||||
{
|
||||
Type t = element.GetType();
|
||||
|
||||
// 扫描所有带 DynamicUI 标记的字段或属性
|
||||
var dynamicFields = new List<FieldDef>();
|
||||
foreach (var member in t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
var uiAttr = member.GetCustomAttribute<DynamicUIAttribute>();
|
||||
if (uiAttr != null)
|
||||
{
|
||||
Type vType = member is FieldInfo f ? f.FieldType : (member as PropertyInfo)?.PropertyType;
|
||||
if (vType != null) dynamicFields.Add(new FieldDef { Member = member, Attr = uiAttr, ValueType = vType });
|
||||
}
|
||||
}
|
||||
|
||||
// 扫描所有带 DynamicUIButton 的方法
|
||||
var dynamicMethods = new List<MethodDef>();
|
||||
foreach (var method in t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
var btnAttr = method.GetCustomAttribute<DynamicUIButtonAttribute>();
|
||||
if (btnAttr != null && method.GetParameters().Length == 0)
|
||||
{
|
||||
dynamicMethods.Add(new MethodDef { Method = method, Attr = btnAttr });
|
||||
}
|
||||
}
|
||||
|
||||
// 按照 Group 归类准备流式渲染
|
||||
var allGroups = dynamicFields.Select(f => f.Attr.Group)
|
||||
.Concat(dynamicMethods.Select(m => m.Attr.Group))
|
||||
.Distinct().ToList();
|
||||
|
||||
foreach (var groupName in allGroups)
|
||||
{
|
||||
var container = inspector.GenerateContainer(groupName);
|
||||
|
||||
var fieldsInGroup = dynamicFields.Where(f => f.Attr.Group == groupName).ToList();
|
||||
var methodsInGroup = dynamicMethods.Where(m => m.Attr.Group == groupName).ToList();
|
||||
|
||||
// ======== 智能栅格打包推演 ========
|
||||
List<FieldDef> currentLineBuffer = new List<FieldDef>();
|
||||
int currentSpanCount = 0; // 一行容量最高是 3
|
||||
|
||||
// 先排变量
|
||||
foreach (var field in fieldsInGroup)
|
||||
{
|
||||
int span = GetEffectiveSpan(field);
|
||||
span = Mathf.Clamp(span, 1, 3);
|
||||
|
||||
// 如果该行的槽被塞满了或者装不下了
|
||||
if (currentSpanCount > 0 && currentSpanCount + span > 3)
|
||||
{
|
||||
FlushLine(element, inspector, container, currentLineBuffer, 3);
|
||||
currentLineBuffer.Clear();
|
||||
currentSpanCount = 0;
|
||||
}
|
||||
|
||||
// 特殊兼容:由于 GridLayoutGroup 的强制统一 cellSize, 我们如果在同一行混搭不同 Span 宽度的,反而会让它变形。
|
||||
// 因此若当前这行的空间要求和前一个需求跨度不一致,也必须强行断点分层!
|
||||
if (currentLineBuffer.Count > 0)
|
||||
{
|
||||
var lastSpan = GetEffectiveSpan(currentLineBuffer[0]);
|
||||
if (span != lastSpan)
|
||||
{
|
||||
FlushLine(element, inspector, container, currentLineBuffer, GetHighestSpanRequirement(currentLineBuffer));
|
||||
currentLineBuffer.Clear();
|
||||
currentSpanCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
currentLineBuffer.Add(field);
|
||||
currentSpanCount += span;
|
||||
}
|
||||
if (currentLineBuffer.Count > 0) FlushLine(element, inspector, container, currentLineBuffer, GetHighestSpanRequirement(currentLineBuffer));
|
||||
|
||||
// ======== 最后把按钮并排排好 ========
|
||||
if (methodsInGroup.Count > 0)
|
||||
{
|
||||
var btnSubcontainer = container.GenerateSubcontainer(3); // 按钮统统放在 1/3 的槽里(你可改规则)
|
||||
foreach (var method in methodsInGroup)
|
||||
{
|
||||
MethodInfo mInfo = method.Method;
|
||||
// 通过强行抓取生成 UnityAction 给工厂
|
||||
UnityAction action = () => { mInfo.Invoke(element, null); element.Refresh(); };
|
||||
string n = string.IsNullOrEmpty(method.Attr.Name) ? mInfo.Name : method.Attr.Name;
|
||||
inspector.GenerateButton(element, btnSubcontainer, n, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 核心工厂发射器
|
||||
private static void FlushLine(IBaseElement element, IHaveInspection inspector, DynamicUIContainer container, List<FieldDef> fields, int lineSpanCapacity)
|
||||
{
|
||||
// 如果一行要放 3 份(Span 都是 1 拼成的),那格子数量也是 3(600/3=200一个)
|
||||
// 但是如果是独占的(Span 都是 3),格子数量反而应该是 1(600/1=600一个!)
|
||||
// 为了防止排版错开变形,我们通过 3 / span 来决定 Subcontainer 内部允许的等分元素数量。
|
||||
int subcontainerDivision = Mathf.Max(1, Mathf.RoundToInt(3f / lineSpanCapacity));
|
||||
|
||||
float rowHeight = GetHighestHeightRequirement(fields);
|
||||
var sub = container.GenerateSubcontainer(subcontainerDivision, rowHeight);
|
||||
|
||||
foreach (var fd in fields)
|
||||
{
|
||||
string title = string.IsNullOrEmpty(fd.Attr.Name) ? fd.Member.Name : fd.Attr.Name;
|
||||
string pName = fd.Member.Name;
|
||||
|
||||
if (fd.Attr.ReadOnly)
|
||||
{
|
||||
var val = ReflectionHelper.GetDeepValue(element, pName);
|
||||
inspector.GenerateHintText(element, sub, $"{title}: {val}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 智能类型分流
|
||||
if (fd.Attr is DynamicUIEmissionColorAttribute emissionAttr)
|
||||
{
|
||||
// 使用之前为了消除扩展方法调不出来的尴尬而专门暴露的强转/普通调用,我们直接这里也安全使用
|
||||
IHaveInspection rawInspector = inspector as IHaveInspection;
|
||||
if(rawInspector != null) rawInspector.GenerateEmissionColorPicker(element, sub, title, emissionAttr.EmissionEnabledName, pName, emissionAttr.EmissionIntensityName);
|
||||
}
|
||||
else if (fd.ValueType == typeof(bool))
|
||||
{
|
||||
inspector.GenerateToggle(element, sub, title, pName);
|
||||
}
|
||||
else if (fd.ValueType == typeof(Vector2))
|
||||
{
|
||||
inspector.GenerateVector2InputField(element, sub, title, pName, fd.Attr.AutoUpdate);
|
||||
}
|
||||
else if (fd.ValueType == typeof(Vector3))
|
||||
{
|
||||
inspector.GenerateVector3InputField(element, sub, title, pName, fd.Attr.AutoUpdate);
|
||||
}
|
||||
else if (fd.ValueType == typeof(Color))
|
||||
{
|
||||
inspector.GenerateBaseColorPicker(element, sub, title, pName);
|
||||
}
|
||||
else if (fd.ValueType.IsEnum)
|
||||
{
|
||||
inspector.GenerateDropdown(element, sub, title, fd.ValueType, pName);
|
||||
}
|
||||
else if (fd.Attr is DynamicUISliderAttribute sliderAttr)
|
||||
{
|
||||
inspector.GenerateSlider(element, sub, title, pName, sliderAttr.Min, sliderAttr.Max, sliderAttr.WholeNumbers);
|
||||
}
|
||||
else // 容错给普通的 InputField
|
||||
{
|
||||
inspector.GenerateInputField(element, sub, title, pName, fd.Attr.AutoUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int SmartInferSpan(Type t)
|
||||
{
|
||||
if (t == typeof(bool)) return 1;
|
||||
if (t == typeof(float) || t == typeof(int) || t == typeof(string)) return 1;
|
||||
if (t.IsEnum) return 1;
|
||||
if (t == typeof(Vector2)) return 2;
|
||||
if (t == typeof(Vector3) || t == typeof(Color)) return 3; // 巨型组件通篇独占一行
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int GetHighestSpanRequirement(List<FieldDef> fields)
|
||||
{
|
||||
int highest = 1;
|
||||
foreach (var f in fields)
|
||||
{
|
||||
int span = GetEffectiveSpan(f);
|
||||
if (span > highest) highest = span;
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
private static int GetEffectiveSpan(FieldDef fd)
|
||||
{
|
||||
return fd.Attr.Span > 0 ? fd.Attr.Span : SmartInferSpan(fd.ValueType);
|
||||
}
|
||||
|
||||
private static float SmartInferHeight(FieldDef fd)
|
||||
{
|
||||
// EmissionColorPicker 有 Toggle/RGB滑块/Intensity输入框,高度明显大于 BaseColorPicker
|
||||
if (fd.Attr is DynamicUIEmissionColorAttribute) return 320f;
|
||||
if (fd.ValueType == typeof(Color)) return 280f;
|
||||
// 多数基础组件默认为 100
|
||||
return 100f;
|
||||
}
|
||||
|
||||
private static float GetHighestHeightRequirement(List<FieldDef> fields)
|
||||
{
|
||||
float highest = 100f;
|
||||
foreach (var f in fields)
|
||||
{
|
||||
float height = f.Attr.Height > 0 ? f.Attr.Height : SmartInferHeight(f);
|
||||
if (height > highest) highest = height;
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0bc252acb576104aaff0846e4c1e136
|
||||
@@ -13,6 +13,11 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Inspector 工厂接口 —— 提供底层 UI 控件的实例化方法。
|
||||
/// 外部代码应通过 <see cref="InspectorBuilder"/> 构建 Inspector,
|
||||
/// 而非直接调用本接口的 Generate 方法。
|
||||
/// </summary>
|
||||
public interface IHaveInspection
|
||||
{
|
||||
public RectTransform WindowRect { get; set; }
|
||||
@@ -226,6 +231,7 @@ namespace Ichni.Editor
|
||||
return hintText;
|
||||
}
|
||||
|
||||
[Obsolete("GenerateParameterText 已无外部调用者,请使用 InspectorBuilder.HintText() 替代。")]
|
||||
public DynamicUIParameterText GenerateParameterText(IBaseElement baseElement, DynamicUISubcontainer subcontainer,
|
||||
string title, string parameterName, bool isAutoUpdate = false)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace Ichni.Editor
|
||||
public Dictionary<string, DynamicUISubcontainer> MarkedSubcontainers { get; set; }
|
||||
public Dictionary<string, DynamicUIElement> MarkedElements { get; set; }
|
||||
|
||||
/// <summary> Drawer 注册表单例的便捷访问 </summary>
|
||||
public DrawerRegistry DrawerRegistry => DrawerRegistry.Instance;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
WindowRect = inspectorRect;
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.RhythmGame;
|
||||
using UnityEngine;
|
||||
namespace Ichni.Editor
|
||||
{
|
||||
public static class StandardInspectionElement
|
||||
{
|
||||
private static IHaveInspection inspector => EditorManager.instance.uiManager.inspector;
|
||||
private static Inspector inspectorUI => EditorManager.instance.uiManager.inspector;
|
||||
public static void GenerateForTransform(GameElement gameElement, DynamicUIContainer generateContainer = null)//关于有Transform
|
||||
{
|
||||
if (generateContainer is null)
|
||||
{
|
||||
generateContainer = inspector.GenerateContainer("Generate Elements");
|
||||
}
|
||||
var animationSubcontainer = generateContainer.GenerateSubcontainer(3);
|
||||
var displacementButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Displacement", () =>
|
||||
{
|
||||
Displacement.GenerateElement("New Displacement", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
|
||||
}); //位移
|
||||
|
||||
var swirlButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Swirl", () =>
|
||||
{
|
||||
Swirl.GenerateElement("New Swirl", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
|
||||
}); //旋转
|
||||
var scaleButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Scale", () =>
|
||||
{
|
||||
Scale.GenerateElement("New Scale", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
new FlexibleFloat(true), new FlexibleFloat(true), new FlexibleFloat(true));
|
||||
}); //缩放
|
||||
var LookAtButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Look At",
|
||||
() => LookAt.GenerateElement("New Look At", Guid.NewGuid(),
|
||||
new List<string>(), true, gameElement, null, new FlexibleBool()));
|
||||
var displacementTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Displacement Tracker", () =>
|
||||
{
|
||||
DisplacementTracker.GenerateElement("New Displacement Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
null, 0f);
|
||||
});
|
||||
var swirlTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Swirl Tracker", () =>
|
||||
{
|
||||
SwirlTracker.GenerateElement("New Swirl Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
null, 0f);
|
||||
}); var ScaleTrackerButton = inspector.GenerateButton(gameElement, animationSubcontainer, "Scale Tracker", () =>
|
||||
{
|
||||
ScaleTracker.GenerateElement("New Scale Tracker", Guid.NewGuid(), new List<string>(), true, gameElement,
|
||||
null, 0f);
|
||||
});
|
||||
}
|
||||
public static void GenerateForLoading()
|
||||
{
|
||||
inspectorUI.ClearInspector();
|
||||
var container = inspector.GenerateContainer("Loading");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97779e95563721b4e8d4a28bb0d46cb9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -543,16 +543,14 @@ namespace ichni.RhythmGame // [修复] 修正命名空间首字母大写,符
|
||||
{
|
||||
base.SetUpInspector();
|
||||
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Fast Note Tracker");
|
||||
var sub = container.GenerateSubcontainer(2);
|
||||
inspector.GenerateToggle(this, sub, "Enabled", nameof(IsEnabled));
|
||||
// 修正变量名
|
||||
inspector.GenerateInputField(this, sub, "Beat Diver", nameof(BeatDiver));
|
||||
inspector.GenerateToggle(this, sub, "Force refresh (cost++)", nameof(ForceRefresh));
|
||||
inspector.GenerateInputField(this, sub, "Horizon Width", nameof(horizonWidth));
|
||||
inspector.GenerateToggle(this, sub, "Show Note Preview", nameof(showNotePreview));
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Fast Note Tracker")
|
||||
.Toggle(nameof(IsEnabled), "Enabled").Span(2)
|
||||
.InputField(nameof(BeatDiver), "Beat Diver").Span(2)
|
||||
.Toggle(nameof(ForceRefresh), "Force refresh (cost++)").Span(2)
|
||||
.InputField(nameof(horizonWidth), "Horizon Width").Span(2)
|
||||
.Toggle(nameof(showNotePreview), "Show Note Preview").Span(2)
|
||||
.Build();
|
||||
}
|
||||
|
||||
public static FastNoteTracker GenerateElement(string elementName, Guid id, List<string> tags,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -8,13 +7,12 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Camera Field of View");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var fovButton = inspector.GenerateButton(this, subcontainer, "Field of View", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Field of View", nameof(fieldOfView)).SetAsFlexibleFloat();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Camera Field of View")
|
||||
.Button("Field of View", () => insp.GenerateCompositeParameterWindow(this, "Field of View", nameof(fieldOfView)).SetAsFlexibleFloat())
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -7,31 +6,18 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Base Color Change");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var colorRButton = inspector.GenerateButton(this, subcontainer, "Color R", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorGButton = inspector.GenerateButton(this, subcontainer, "Color G", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorBButton = inspector.GenerateButton(this, subcontainer, "Color B", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorAButton = inspector.GenerateButton(this, subcontainer, "Color A", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color A", nameof(colorA)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Base Color",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorA }, new string[] { "R", "G", "B", "A" });
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Base Color Change")
|
||||
.Button("Color R", () => insp.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat())
|
||||
.Button("Color G", () => insp.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat())
|
||||
.Button("Color B", () => insp.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat())
|
||||
.Button("Color A", () => insp.GenerateCompositeParameterWindow(this, "Color A", nameof(colorA)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Base Color",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorA }, new string[] { "R", "G", "B", "A" }))
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -7,31 +6,18 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Emission Color Change");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var colorRButton = inspector.GenerateButton(this, subcontainer, "Color R", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorGButton = inspector.GenerateButton(this, subcontainer, "Color G", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorBButton = inspector.GenerateButton(this, subcontainer, "Color B", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorAButton = inspector.GenerateButton(this, subcontainer, "Color A", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color I", nameof(colorI)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Emission Color",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorI }, new string[] { "R", "G", "B", "I" });
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Emission Color Change")
|
||||
.Button("Color R", () => insp.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat())
|
||||
.Button("Color G", () => insp.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat())
|
||||
.Button("Color B", () => insp.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat())
|
||||
.Button("Color I", () => insp.GenerateCompositeParameterWindow(this, "Color I", nameof(colorI)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Emission Color",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorI }, new string[] { "R", "G", "B", "I" }))
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,37 +15,23 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
|
||||
var container = inspector.GenerateContainer("Property Animation Color");
|
||||
var settings = container.GenerateSubcontainer(3);
|
||||
|
||||
inspector.GenerateInputField(this, settings, "Component Name", nameof(componentName)).AddListenerFunction(() => AfterInitialize());
|
||||
inspector.GenerateInputField(this, settings, "Property Name", nameof(propertyName)).AddListenerFunction(() => AfterInitialize());
|
||||
|
||||
var graphicEditor = inspector.GenerateButton(this, settings, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Property Color",
|
||||
new FlexibleFloat[] { propertyValueR, propertyValueG, propertyValueB, propertyValueA }, new string[] { "R", "G", "B", "A" });
|
||||
});
|
||||
|
||||
var colorRButton = inspector.GenerateButton(this, settings, "Color R", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(propertyValueR)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorGButton = inspector.GenerateButton(this, settings, "Color G", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(propertyValueG)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorBButton = inspector.GenerateButton(this, settings, "Color B", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(propertyValueB)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorAButton = inspector.GenerateButton(this, settings, "Color A", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color A", nameof(propertyValueA)).SetAsFlexibleFloat();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Property Animation Color")
|
||||
.InputField(nameof(componentName), "Component Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.InputField(nameof(propertyName), "Property Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Property Color",
|
||||
new FlexibleFloat[] { propertyValueR, propertyValueG, propertyValueB, propertyValueA },
|
||||
new string[] { "R", "G", "B", "A" }))
|
||||
.Button("Color R", () => insp.GenerateCompositeParameterWindow(this, "Color R", nameof(propertyValueR)).SetAsFlexibleFloat())
|
||||
.Button("Color G", () => insp.GenerateCompositeParameterWindow(this, "Color G", nameof(propertyValueG)).SetAsFlexibleFloat())
|
||||
.Button("Color B", () => insp.GenerateCompositeParameterWindow(this, "Color B", nameof(propertyValueB)).SetAsFlexibleFloat())
|
||||
.Button("Color A", () => insp.GenerateCompositeParameterWindow(this, "Color A", nameof(propertyValueA)).SetAsFlexibleFloat())
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,25 +14,19 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
|
||||
var container = inspector.GenerateContainer("Property Animation Float");
|
||||
var settings = container.GenerateSubcontainer(3);
|
||||
|
||||
inspector.GenerateInputField(this, settings, "Component Name", nameof(componentName)).AddListenerFunction(() => AfterInitialize());
|
||||
inspector.GenerateInputField(this, settings, "Property Name", nameof(propertyName)).AddListenerFunction(() => AfterInitialize());
|
||||
|
||||
var graphicEditor = inspector.GenerateButton(this, settings, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Property Float",
|
||||
new FlexibleFloat[] { propertyValue }, new string[] { "Value" });
|
||||
});
|
||||
|
||||
var floatButton = inspector.GenerateButton(this, settings, "Float Value", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Float Value", nameof(propertyValue)).SetAsFlexibleFloat();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Property Animation Float")
|
||||
.InputField(nameof(componentName), "Component Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.InputField(nameof(propertyName), "Property Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Property Float",
|
||||
new FlexibleFloat[] { propertyValue }, new string[] { "Value" }))
|
||||
.Button("Float Value", () => insp.GenerateCompositeParameterWindow(this, "Float Value", nameof(propertyValue)).SetAsFlexibleFloat())
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,33 +14,21 @@ namespace Ichni.RhythmGame
|
||||
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
|
||||
var container = inspector.GenerateContainer("Property Animation Vector3");
|
||||
var settings = container.GenerateSubcontainer(3);
|
||||
|
||||
inspector.GenerateInputField(this, settings, "Component Name", nameof(componentName)).AddListenerFunction(() => AfterInitialize());
|
||||
inspector.GenerateInputField(this, settings, "Property Name", nameof(propertyName)).AddListenerFunction(() => AfterInitialize());
|
||||
|
||||
var graphicEditor = inspector.GenerateButton(this, settings, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Property Vector3",
|
||||
new FlexibleFloat[] { propertyValueX, propertyValueY, propertyValueZ }, new string[] { "X", "Y", "Z" });
|
||||
});
|
||||
|
||||
var xButton = inspector.GenerateButton(this, settings, "Vector X", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Vector X", nameof(propertyValueX)).SetAsFlexibleFloat();
|
||||
});
|
||||
var yButton = inspector.GenerateButton(this, settings, "Vector Y", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Vector Y", nameof(propertyValueY)).SetAsFlexibleFloat();
|
||||
});
|
||||
var zButton = inspector.GenerateButton(this, settings, "Vector Z", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Vector Z", nameof(propertyValueZ)).SetAsFlexibleFloat();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Property Animation Vector3")
|
||||
.InputField(nameof(componentName), "Component Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.InputField(nameof(propertyName), "Property Name")
|
||||
.OnChanged(() => AfterInitialize())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Property Vector3",
|
||||
new FlexibleFloat[] { propertyValueX, propertyValueY, propertyValueZ }, new string[] { "X", "Y", "Z" }))
|
||||
.Button("Vector X", () => insp.GenerateCompositeParameterWindow(this, "Vector X", nameof(propertyValueX)).SetAsFlexibleFloat())
|
||||
.Button("Vector Y", () => insp.GenerateCompositeParameterWindow(this, "Vector Y", nameof(propertyValueY)).SetAsFlexibleFloat())
|
||||
.Button("Vector Z", () => insp.GenerateCompositeParameterWindow(this, "Vector Z", nameof(propertyValueZ)).SetAsFlexibleFloat())
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,30 +11,36 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Displacement Tracker");
|
||||
var effectSettings = container.GenerateSubcontainer(2);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Displacement");
|
||||
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Displacement", () =>
|
||||
{
|
||||
ICanBeTrackedDisplacement targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedDisplacement>()
|
||||
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
|
||||
if (targetElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
}
|
||||
SetTargetDisplacement(targetElement);
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
string ShowConnection() => targetDisplacement == null ? "No Displacement Connected" : "Connected With: " + ((GameElement)targetDisplacement).elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
|
||||
var interferometerButton = inspector.GenerateButton(this, effectSettings, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Displacement Tracker")
|
||||
.UnboundInputField("Try Get Displacement").WithRef(nameRef)
|
||||
.Button("Connect Displacement", () =>
|
||||
{
|
||||
ICanBeTrackedDisplacement found = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.OfType<ICanBeTrackedDisplacement>()
|
||||
.FirstOrDefault(e => ((GameElement)e).elementName == nameRef.Value?.GetValue<string>());
|
||||
if (found == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
return;
|
||||
}
|
||||
SetTargetDisplacement(found);
|
||||
inspectorMain.SetInspector(this);
|
||||
})
|
||||
.HintText(() => targetDisplacement == null
|
||||
? "No Displacement Connected"
|
||||
: "Connected With: " + ((GameElement)targetDisplacement).elementName)
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,31 +11,36 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Scale Tracker");
|
||||
var effectSettings = container.GenerateSubcontainer(2);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Scale");
|
||||
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Scale", () =>
|
||||
{
|
||||
ICanBeTrackedScale targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedScale>()
|
||||
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
|
||||
if (targetElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
}
|
||||
targetScale = targetElement;
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
string ShowConnection() => targetScale == null ? "No Scale Connected" : "Connected With: " + ((GameElement)targetScale).elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
|
||||
var interferometerButton = inspector.GenerateButton(this, effectSettings, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Scale Tracker")
|
||||
.UnboundInputField("Try Get Scale").WithRef(nameRef)
|
||||
.Button("Connect Scale", () =>
|
||||
{
|
||||
ICanBeTrackedScale found = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.OfType<ICanBeTrackedScale>()
|
||||
.FirstOrDefault(e => ((GameElement)e).elementName == nameRef.Value?.GetValue<string>());
|
||||
if (found == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
return;
|
||||
}
|
||||
targetScale = found;
|
||||
inspectorMain.SetInspector(this);
|
||||
})
|
||||
.HintText(() => targetScale == null
|
||||
? "No Scale Connected"
|
||||
: "Connected With: " + ((GameElement)targetScale).elementName)
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,31 +11,36 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Swirl Tracker");
|
||||
var effectSettings = container.GenerateSubcontainer(2);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Swirl");
|
||||
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Swirl", () =>
|
||||
{
|
||||
ICanBeTrackedSwirl targetElement = EditorManager.instance.beatmapContainer.gameElementList.OfType<ICanBeTrackedSwirl>()
|
||||
.First(e => ((GameElement)e).elementName == connectedGameElementInputField.GetValue<string>());
|
||||
if (targetElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
}
|
||||
targetSwirl = targetElement;
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
string ShowConnection() => targetSwirl == null ? "No Swirl Connected" : "Connected With: " + ((GameElement)targetSwirl).elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
var InputField = inspector.GenerateInputField(this, effectSettings, "Offset", nameof(TimeOffset));
|
||||
var interferometerButton = inspector.GenerateButton(this, effectSettings, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Swirl Tracker")
|
||||
.UnboundInputField("Try Get Swirl").WithRef(nameRef)
|
||||
.Button("Connect Swirl", () =>
|
||||
{
|
||||
ICanBeTrackedSwirl found = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.OfType<ICanBeTrackedSwirl>()
|
||||
.FirstOrDefault(e => ((GameElement)e).elementName == nameRef.Value?.GetValue<string>());
|
||||
if (found == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
return;
|
||||
}
|
||||
targetSwirl = found;
|
||||
inspectorMain.SetInspector(this);
|
||||
})
|
||||
.HintText(() => targetSwirl == null
|
||||
? "No Swirl Connected"
|
||||
: "Connected With: " + ((GameElement)targetSwirl).elementName)
|
||||
.InputField(nameof(TimeOffset), "Offset")
|
||||
.Button("Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(),
|
||||
new List<string>(), true, this, InterferomType.Additive, Vector3.zero);
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -11,11 +7,12 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Vector3 Interferometer");
|
||||
var subcontainer = container.GenerateSubcontainer(1);
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Interferom Value", nameof(InterferomValueVector3));
|
||||
inspector.GenerateDropdown(this, subcontainer, "Interferom Type", typeof(InterferomType), nameof(InterferomType));
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Vector3 Interferometer")
|
||||
.Vector3Field(nameof(InterferomValueVector3), "Interferom Value")
|
||||
.Dropdown<InterferomType>(nameof(InterferomType), "Interferom Type")
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -7,32 +6,18 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Track Global Color Change");
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var colorRButton = inspector.GenerateButton(this, subcontainer, "Color R", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorGButton = inspector.GenerateButton(this, subcontainer, "Color G", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorBButton = inspector.GenerateButton(this, subcontainer, "Color B", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat();
|
||||
});
|
||||
var colorAButton = inspector.GenerateButton(this, subcontainer, "Color A", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Color A", nameof(colorA)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Track Global Color Change",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorA }, new string[] { "ColorR", "ColorG", "ColorB", "ColorA" });
|
||||
});
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Track Global Color Change")
|
||||
.Button("Color R", () => insp.GenerateCompositeParameterWindow(this, "Color R", nameof(colorR)).SetAsFlexibleFloat())
|
||||
.Button("Color G", () => insp.GenerateCompositeParameterWindow(this, "Color G", nameof(colorG)).SetAsFlexibleFloat())
|
||||
.Button("Color B", () => insp.GenerateCompositeParameterWindow(this, "Color B", nameof(colorB)).SetAsFlexibleFloat())
|
||||
.Button("Color A", () => insp.GenerateCompositeParameterWindow(this, "Color A", nameof(colorA)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Track Global Color Change",
|
||||
new FlexibleFloat[] { colorR, colorG, colorB, colorA }, new string[] { "ColorR", "ColorG", "ColorB", "ColorA" }))
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -7,14 +6,13 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Track Total Time Change");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var totalTimeButton = inspector.GenerateButton(this, subcontainer, "Total Time", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Total Time", nameof(totalTime)).SetAsFlexibleFloat();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Track Total Time Change")
|
||||
.Button("Total Time", () => insp.GenerateCompositeParameterWindow(this, "Total Time", nameof(totalTime)).SetAsFlexibleFloat())
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,35 +9,22 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Displacement");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var positionXButton = inspector.GenerateButton(this, subcontainer, "Position X", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Position X", nameof(positionX)).SetAsFlexibleFloat();
|
||||
});
|
||||
var positionYButton = inspector.GenerateButton(this, subcontainer, "Position Y", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Position Y", nameof(positionY)).SetAsFlexibleFloat();
|
||||
});
|
||||
var positionZButton = inspector.GenerateButton(this, subcontainer, "Position Z", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Position Z", nameof(positionZ)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Displacement",
|
||||
new FlexibleFloat[] { positionX, positionY, positionZ }, new string[] { "PosX", "PosY", "PosZ" });
|
||||
});
|
||||
var subcontainer2 = container.GenerateSubcontainer(1);
|
||||
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Displacement")
|
||||
.Button("Position X", () => insp.GenerateCompositeParameterWindow(this, "Position X", nameof(positionX)).SetAsFlexibleFloat())
|
||||
.Button("Position Y", () => insp.GenerateCompositeParameterWindow(this, "Position Y", nameof(positionY)).SetAsFlexibleFloat())
|
||||
.Button("Position Z", () => insp.GenerateCompositeParameterWindow(this, "Position Z", nameof(positionZ)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Displacement",
|
||||
new FlexibleFloat[] { positionX, positionY, positionZ }, new string[] { "PosX", "PosY", "PosZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,32 +8,35 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
IHaveInspection inspection = inspectorMain;
|
||||
|
||||
var container = inspector.GenerateContainer("Look At");
|
||||
var effectSettings = container.GenerateSubcontainer(2);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Try Get Element");
|
||||
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Game Element", () =>
|
||||
{
|
||||
GameElement targetElement = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.First(e => e.elementName == connectedGameElementInputField.GetValue<string>());
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
|
||||
if (targetElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
}
|
||||
|
||||
lookAtObject = targetElement;
|
||||
inspectorMain.SetInspector(this);
|
||||
});
|
||||
string ShowConnection() => lookAtObject == null ? "No Game Element Connected" : "Connected With: " + lookAtObject.elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
|
||||
var enablingButton = inspector.GenerateButton(this, effectSettings, "Enabling", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Enabling", nameof(enabling)).SetAsFlexibleBool();
|
||||
});
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Look At")
|
||||
.UnboundInputField("Try Get Element").WithRef(nameRef)
|
||||
.Button("Connect Game Element", () =>
|
||||
{
|
||||
GameElement found = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.FirstOrDefault(e => e.elementName == nameRef.Value?.GetValue<string>());
|
||||
if (found == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.yellow);
|
||||
return;
|
||||
}
|
||||
lookAtObject = found;
|
||||
inspectorMain.SetInspector(this);
|
||||
})
|
||||
.HintText(() => lookAtObject == null
|
||||
? "No Game Element Connected"
|
||||
: "Connected With: " + lookAtObject.elementName)
|
||||
.Button("Enabling", () =>
|
||||
{
|
||||
inspection.GenerateCompositeParameterWindow(this, "Enabling", nameof(enabling))
|
||||
.SetAsFlexibleBool();
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,35 +10,22 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Scale");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var scaleXButton = inspector.GenerateButton(this, subcontainer, "Scale X", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Scale X", nameof(scaleX)).SetAsFlexibleFloat();
|
||||
});
|
||||
var scaleYButton = inspector.GenerateButton(this, subcontainer, "Scale Y", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Scale Y", nameof(scaleY)).SetAsFlexibleFloat();
|
||||
});
|
||||
var scaleZButton = inspector.GenerateButton(this, subcontainer, "Scale Z", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Scale Z", nameof(scaleZ)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Scale",
|
||||
new FlexibleFloat[] { scaleX, scaleY, scaleZ },
|
||||
new string[] { "ScaleX", "ScaleY", "ScaleZ" });
|
||||
});
|
||||
var subcontainer2 = container.GenerateSubcontainer(1);
|
||||
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Scale")
|
||||
.Button("Scale X", () => insp.GenerateCompositeParameterWindow(this, "Scale X", nameof(scaleX)).SetAsFlexibleFloat())
|
||||
.Button("Scale Y", () => insp.GenerateCompositeParameterWindow(this, "Scale Y", nameof(scaleY)).SetAsFlexibleFloat())
|
||||
.Button("Scale Z", () => insp.GenerateCompositeParameterWindow(this, "Scale Z", nameof(scaleZ)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Scale",
|
||||
new FlexibleFloat[] { scaleX, scaleY, scaleZ },
|
||||
new string[] { "ScaleX", "ScaleY", "ScaleZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,35 +10,22 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
base.SetUpInspector();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Swirl");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var eulerAngleXButton = inspector.GenerateButton(this, subcontainer, "Euler Angle X", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Euler Angle X", nameof(eulerAngleX)).SetAsFlexibleFloat();
|
||||
});
|
||||
var eulerAngleYButton = inspector.GenerateButton(this, subcontainer, "Euler Angle Y", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Euler Angle Y", nameof(eulerAngleY)).SetAsFlexibleFloat();
|
||||
});
|
||||
var eulerAngleZButton = inspector.GenerateButton(this, subcontainer, "Euler Angle Z", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Euler Angle Z", nameof(eulerAngleZ)).SetAsFlexibleFloat();
|
||||
});
|
||||
var graphicEditor = inspector.GenerateButton(this, subcontainer, "GraphicEditor", () =>
|
||||
{
|
||||
inspector.GenerateGraphicalFlexibleFloatWindow(this, "Swirl",
|
||||
new FlexibleFloat[] { eulerAngleX, eulerAngleY, eulerAngleZ },
|
||||
new string[] { "EulerX", "EulerY", "EulerZ" });
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var subcontainer2 = container.GenerateSubcontainer(1);
|
||||
var valuetext = inspector.GenerateParameterText(this, subcontainer2, "value:", nameof(PreviewValue), true);
|
||||
var interferometerButton = inspector.GenerateButton(this, subcontainer2, "Interferometer", () =>
|
||||
{
|
||||
Vector3Interferometer.GenerateElement("New Vector3 Interferometer", Guid.NewGuid(), new List<string>(), true,
|
||||
this, InterferomType.Additive, Vector3.zero);
|
||||
});
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Swirl")
|
||||
.Button("Euler Angle X", () => insp.GenerateCompositeParameterWindow(this, "Euler Angle X", nameof(eulerAngleX)).SetAsFlexibleFloat())
|
||||
.Button("Euler Angle Y", () => insp.GenerateCompositeParameterWindow(this, "Euler Angle Y", nameof(eulerAngleY)).SetAsFlexibleFloat())
|
||||
.Button("Euler Angle Z", () => insp.GenerateCompositeParameterWindow(this, "Euler Angle Z", nameof(eulerAngleZ)).SetAsFlexibleFloat())
|
||||
.Button("GraphicEditor", () => insp.GenerateGraphicalFlexibleFloatWindow(this, "Swirl",
|
||||
new FlexibleFloat[] { eulerAngleX, eulerAngleY, eulerAngleZ },
|
||||
new string[] { "EulerX", "EulerY", "EulerZ" }))
|
||||
.ParameterText(nameof(PreviewValue), "value:", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Button("Interferometer", () => Vector3Interferometer.GenerateElement("New Vector3 Interferometer",
|
||||
Guid.NewGuid(), new List<string>(), true, this, InterferomType.Additive, Vector3.zero))
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,38 +11,57 @@ namespace Ichni.RhythmGame
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Color");
|
||||
|
||||
// ColorSubmodule 的 BaseColorPicker ↔ HsvDrawer 双向引用需要
|
||||
// 直接操作控件实例,使用 RawSection 处理这一复杂交互
|
||||
var builder = InspectorBuilder.For(this);
|
||||
|
||||
if ((attachedGameElement as IHaveColorSubmodule).haveBaseColor)
|
||||
{
|
||||
var subBase = container.GenerateSubcontainer(1, 280f);
|
||||
var baseColor = inspector.GenerateBaseColorPicker(this, subBase, "Base Color", nameof(originalBaseColor));
|
||||
baseColor.AddListenerFunction(Refresh);
|
||||
var hsvDrawer = inspector.GenerateHsvDrawer(this, subBase, "HSV", nameof(originalBaseColor));
|
||||
hsvDrawer.AddListenerFunction(Refresh);
|
||||
baseColor.hsvDrawer = hsvDrawer;
|
||||
hsvDrawer.baseColorPicker = baseColor;
|
||||
if (attachedGameElement.childElementList.Exists(x => x is BaseColorChange))
|
||||
builder.RawSection("Color", int.MaxValue, (insp, container) =>
|
||||
{
|
||||
baseColor.title.text += " (Occupied by Animation)";
|
||||
baseColor.canvasGroup.interactable = false;
|
||||
hsvDrawer.title.text += " (Occupied by Animation)";
|
||||
hsvDrawer.gameObject.SetActive(false);
|
||||
}
|
||||
bool occupiedByAnimation = attachedGameElement.childElementList.Exists(x => x is BaseColorChange);
|
||||
|
||||
var subBase = container.GenerateSubcontainer(1, 280f);
|
||||
var baseColor = insp.GenerateBaseColorPicker(this, subBase, "Base Color", nameof(originalBaseColor));
|
||||
baseColor.AddListenerFunction(Refresh);
|
||||
var hsvDrawer = insp.GenerateHsvDrawer(this, subBase, "HSV", nameof(originalBaseColor));
|
||||
hsvDrawer.AddListenerFunction(Refresh);
|
||||
|
||||
// 双向引用
|
||||
baseColor.hsvDrawer = hsvDrawer;
|
||||
hsvDrawer.baseColorPicker = baseColor;
|
||||
|
||||
if (occupiedByAnimation)
|
||||
{
|
||||
baseColor.title.text += " (Occupied by Animation)";
|
||||
baseColor.canvasGroup.interactable = false;
|
||||
hsvDrawer.title.text += " (Occupied by Animation)";
|
||||
hsvDrawer.gameObject.SetActive(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if ((attachedGameElement as IHaveColorSubmodule).haveEmissionColor)
|
||||
{
|
||||
var subEmission = container.GenerateSubcontainer(1, 320f);
|
||||
var emissionColor = inspector.GenerateEmissionColorPicker(this, subEmission, "Emission Color",
|
||||
nameof(emissionEnabled), nameof(originalEmissionColor), nameof(originalEmissionIntensity));
|
||||
emissionColor.AddListenerFunction(Refresh);
|
||||
|
||||
if (attachedGameElement.childElementList.Exists(x => x is EmissionColorChange))
|
||||
builder.RawSection("Emission", int.MaxValue, (insp, container) =>
|
||||
{
|
||||
emissionColor.title.text += " (Occupied by Animation)";
|
||||
emissionColor.canvasGroup.interactable = false;
|
||||
}
|
||||
bool occupiedByAnimation = attachedGameElement.childElementList.Exists(x => x is EmissionColorChange);
|
||||
|
||||
var subEmission = container.GenerateSubcontainer(1, 320f);
|
||||
var emissionColor = insp.GenerateEmissionColorPicker(this, subEmission, "Emission Color",
|
||||
nameof(emissionEnabled), nameof(originalEmissionColor), nameof(originalEmissionIntensity));
|
||||
emissionColor.AddListenerFunction(Refresh);
|
||||
|
||||
if (occupiedByAnimation)
|
||||
{
|
||||
emissionColor.title.text += " (Occupied by Animation)";
|
||||
emissionColor.canvasGroup.interactable = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
builder.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,35 +8,38 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
foreach (var effect in effectCollection)
|
||||
{
|
||||
var container = inspector.GenerateContainer(effect.Key);
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var effectNameInputField = inspector.GenerateInputField(subcontainer, "Effect Name");
|
||||
var addEffectButton = inspector.GenerateButton(this, subcontainer, "Add Effect", () =>
|
||||
{
|
||||
if (EffectCollection.TryGetValue(effectNameInputField.GetValue<string>(), out var factory))
|
||||
{
|
||||
EffectBase newEffect = factory.Invoke();
|
||||
newEffect.attachedGameElement = attachedGameElement;
|
||||
var list = effectCollection[effect.Key];
|
||||
if (list.Count > 0)
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
string effectKey = effect.Key;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section(effectKey)
|
||||
.UnboundInputField("Effect Name").WithRef(nameRef)
|
||||
.Button("Add Effect", () =>
|
||||
{
|
||||
var last = list[list.Count - 1];
|
||||
newEffect.CopyParametersFrom(last);
|
||||
}
|
||||
list.Add(newEffect);
|
||||
newEffect.AccommodatingList = list;
|
||||
inspectorMain.SetInspector(attachedGameElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWindow.Log("Effect Type not found.", Color.yellow);
|
||||
}
|
||||
});
|
||||
if (EffectCollection.TryGetValue(nameRef.Value?.GetValue<string>(), out var factory))
|
||||
{
|
||||
EffectBase newEffect = factory.Invoke();
|
||||
newEffect.attachedGameElement = attachedGameElement;
|
||||
var list = effectCollection[effectKey];
|
||||
if (list.Count > 0)
|
||||
{
|
||||
var last = list[list.Count - 1];
|
||||
newEffect.CopyParametersFrom(last);
|
||||
}
|
||||
list.Add(newEffect);
|
||||
newEffect.AccommodatingList = list;
|
||||
inspectorMain.SetInspector(attachedGameElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWindow.Log("Effect Type not found.", Color.yellow);
|
||||
}
|
||||
})
|
||||
.Build();
|
||||
|
||||
foreach (var effectBase in effect.Value)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -7,21 +6,30 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Time Duration");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
var overrideToggle = inspector.GenerateToggle(this, subcontainer, "Override Duration", nameof(isOverridingDuration));
|
||||
var startTimeInputField = inspector.GenerateInputField(this, subcontainer, "Start Time", nameof(startTime));
|
||||
var endTimeInputField = inspector.GenerateInputField(this, subcontainer, "End Time", nameof(endTime));
|
||||
|
||||
void SetInputFieldInteractable(bool interactable)
|
||||
{
|
||||
startTimeInputField.inputField.interactable = interactable;
|
||||
endTimeInputField.inputField.interactable = interactable;
|
||||
}
|
||||
|
||||
SetInputFieldInteractable(isOverridingDuration);
|
||||
overrideToggle.AddListenerFunction(() => SetInputFieldInteractable(isOverridingDuration));
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Time Duration")
|
||||
.Toggle(nameof(isOverridingDuration), "Override Duration")
|
||||
.OnChanged(() =>
|
||||
{
|
||||
var insp = EditorManager.instance.uiManager.inspector as IHaveInspection;
|
||||
if (insp.MarkedElements.TryGetValue("tdStartTime", out var st))
|
||||
{
|
||||
st.canvasGroup.interactable = isOverridingDuration;
|
||||
st.canvasGroup.alpha = isOverridingDuration ? 1f : 0.5f;
|
||||
}
|
||||
if (insp.MarkedElements.TryGetValue("tdEndTime", out var et))
|
||||
{
|
||||
et.canvasGroup.interactable = isOverridingDuration;
|
||||
et.canvasGroup.alpha = isOverridingDuration ? 1f : 0.5f;
|
||||
}
|
||||
})
|
||||
.InputField(nameof(startTime), "Start Time")
|
||||
.EnabledIf(() => isOverridingDuration)
|
||||
.Mark("tdStartTime")
|
||||
.InputField(nameof(endTime), "End Time")
|
||||
.EnabledIf(() => isOverridingDuration)
|
||||
.Mark("tdEndTime")
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,33 +7,28 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var builder = InspectorBuilder.For(this)
|
||||
.Section("Transform")
|
||||
.Vector3Field(nameof(originalPosition), "Start Position")
|
||||
.AutoUpdate().OnChanged(Refresh)
|
||||
.Vector3Field(nameof(originalEulerAngles), "Start Rotation")
|
||||
.AutoUpdate().OnChanged(Refresh)
|
||||
.Vector3Field(nameof(originalScale), "Start Scale")
|
||||
.AutoUpdate().OnChanged(Refresh)
|
||||
.ParameterText(nameof(currentPosition), "Current Position", autoUpdate: true)
|
||||
.Span(3)
|
||||
.ParameterText(nameof(currentEulerAngles), "Current Rotation", autoUpdate: true)
|
||||
.Span(3);
|
||||
|
||||
var container = inspector.GenerateContainer("Transform");
|
||||
var subcontainer = container.GenerateSubcontainer(1);
|
||||
var originalPosInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Position", nameof(originalPosition), true);
|
||||
var originalRotInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Rotation", nameof(originalEulerAngles), true);
|
||||
var originalScaleInputField =
|
||||
inspector.GenerateVector3InputField(this, subcontainer, "Start Scale", nameof(originalScale), true);
|
||||
var currentPosText =
|
||||
inspector.GenerateParameterText(this, subcontainer, "Current Position", nameof(currentPosition), true);
|
||||
var currentRotText =
|
||||
inspector.GenerateParameterText(this, subcontainer, "Current Rotation", nameof(currentEulerAngles), true);
|
||||
|
||||
if (attachedGameElement is PathNode or Trail) // 如果是PathNode,显示法线方向
|
||||
if (attachedGameElement is PathNode or Trail)
|
||||
{
|
||||
var currentNormalText =
|
||||
inspector.GenerateHintText(this, subcontainer, () => "Normal: " + attachedGameElement.transform.forward);
|
||||
builder.HintText(() => "Normal: " + attachedGameElement.transform.forward)
|
||||
.Span(3);
|
||||
}
|
||||
|
||||
var currentScaleText =
|
||||
inspector.GenerateParameterText(this, subcontainer, "Current Scale", nameof(currentScale), true);
|
||||
|
||||
originalPosInputField.AddListenerFunction(Refresh);
|
||||
originalRotInputField.AddListenerFunction(Refresh);
|
||||
originalScaleInputField.AddListenerFunction(Refresh);
|
||||
builder.ParameterText(nameof(currentScale), "Current Scale", autoUpdate: true)
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,45 +20,45 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
base.SetUpInspector();
|
||||
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Generate");
|
||||
var builder = InspectorBuilder.For(this)
|
||||
.Section("Generate")
|
||||
.Button("Environment Object", () =>
|
||||
TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(),
|
||||
new List<string>(), true, this))
|
||||
.Toggle(nameof(isStatic), "Is Static")
|
||||
.OnChanged(() => gameObject.isStatic = isStatic)
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate Animations")
|
||||
.Button("Base Color Change", () =>
|
||||
BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
));
|
||||
|
||||
var objectSettings = container.GenerateSubcontainer(3);
|
||||
var environmentObjectButton = inspector.GenerateButton(this, objectSettings, "Environment Object",
|
||||
() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this));
|
||||
var isStaticToggle = inspector.GenerateToggle(this, objectSettings, "Is Static", nameof(isStatic))
|
||||
.AddListenerFunction(() => gameObject.isStatic = isStatic);
|
||||
StandardInspectionElement.GenerateForTransform(this, container); //关于有Transform的元素
|
||||
|
||||
var generateAnimation = container.GenerateSubcontainer(3);
|
||||
var generateBaseColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Base Color Change",
|
||||
() => BaseColorChange.GenerateElement("New Base Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this,
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.r, colorSubmodule.originalBaseColor.r, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.g, colorSubmodule.originalBaseColor.g, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.b, colorSubmodule.originalBaseColor.b, animationCurveType: AnimationCurveType.Linear) }),
|
||||
new FlexibleFloat(new List<AnimatedFloat> { new AnimatedFloat(0f, 0.1f, colorSubmodule.originalBaseColor.a, colorSubmodule.originalBaseColor.a, animationCurveType: AnimationCurveType.Linear) })
|
||||
));
|
||||
if (haveEmissionColor)
|
||||
{
|
||||
var generateEmissionColorChangeButton = inspector.GenerateButton(this, generateAnimation, "Emission Color Change",
|
||||
() => EmissionColorChange.GenerateElement("New Emission Color Change", Guid.NewGuid(), new List<string>(), true,
|
||||
this, new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
builder.Button("Emission Color Change", () =>
|
||||
EmissionColorChange.GenerateElement("New Emission Color Change", Guid.NewGuid(),
|
||||
new List<string>(), true, this,
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
}
|
||||
|
||||
var generatePropertyAnimationColor = inspector.GenerateButton(this, generateAnimation, "Property Animation Color",
|
||||
() => PropertyAnimationColor.GenerateElement("New Property Animation Color", Guid.NewGuid(), new List<string>(), true,
|
||||
this, this.GetType().FullName, "", new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
|
||||
var generatePropertyAnimationFloat = inspector.GenerateButton(this, generateAnimation, "Property Animation Float",
|
||||
() => PropertyAnimationFloat.GenerateElement("New Property Animation Float", Guid.NewGuid(), new List<string>(), true,
|
||||
this, this.GetType().FullName, "", new FlexibleFloat()));
|
||||
|
||||
var generatePropertyAnimationVector3 = inspector.GenerateButton(this, generateAnimation, "Property Animation Vector3",
|
||||
() => PropertyAnimationVector3.GenerateElement("New Property Animation Vector3", Guid.NewGuid(), new List<string>(), true,
|
||||
this, this.GetType().FullName, "", new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()));
|
||||
|
||||
builder
|
||||
.Button("Property Animation Color", () =>
|
||||
PropertyAnimationColor.GenerateElement("New Property Animation Color", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "",
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()))
|
||||
.Button("Property Animation Float", () =>
|
||||
PropertyAnimationFloat.GenerateElement("New Property Animation Float", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "", new FlexibleFloat()))
|
||||
.Button("Property Animation Vector3", () =>
|
||||
PropertyAnimationVector3.GenerateElement("New Property Animation Vector3", Guid.NewGuid(),
|
||||
new List<string>(), true, this, GetType().FullName, "",
|
||||
new FlexibleFloat(), new FlexibleFloat(), new FlexibleFloat()))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -22,83 +22,71 @@ namespace Ichni.RhythmGame
|
||||
#region [面板绘制] Inspector GUI
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Generate");
|
||||
|
||||
var generateBase = container.GenerateSubcontainer(3);
|
||||
var folderButton = inspector.GenerateButton(this, generateBase, "Folder",
|
||||
() => ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, this));
|
||||
var trackButton = inspector.GenerateButton(this, generateBase, "Track",
|
||||
() => Track.GenerateElement("New Track", Guid.NewGuid(), new List<string>(), true, this));
|
||||
var cameraButton = inspector.GenerateButton(this, generateBase, "Camera",
|
||||
() => GameCamera.GenerateElement("New Camera", Guid.NewGuid(), new List<string>(), true, this,
|
||||
GameCamera.CameraViewType.Perspective, 60, 10));
|
||||
var crossTrackPoint = inspector.GenerateButton(this, generateBase, "Cross Track Point",
|
||||
() => CrossTrackPoint.GenerateElement("New Cross Track Point", Guid.NewGuid(), new List<string>(), true,
|
||||
this, new FlexibleInt(), new FlexibleFloat()));
|
||||
|
||||
StandardInspectionElement.GenerateForTransform(this, container); // 关于有Transform的元素
|
||||
|
||||
var generateNote = container.GenerateSubcontainer(3);
|
||||
var tapButton = inspector.GenerateButton(this, generateNote, "Tap",
|
||||
() => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f));
|
||||
var stayButton = inspector.GenerateButton(this, generateNote, "Stay",
|
||||
() => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f));
|
||||
var holdButton = inspector.GenerateButton(this, generateNote, "Hold",
|
||||
() => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f));
|
||||
var flickButton = inspector.GenerateButton(this, generateNote, "Flick",
|
||||
() => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f,
|
||||
new List<Vector2>()));
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Generate", sectionOrder: 10)
|
||||
.Button("Folder", () => ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Track", () => Track.GenerateElement("New Track", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Camera", () => GameCamera.GenerateElement("New Camera", Guid.NewGuid(), new List<string>(), true, this, GameCamera.CameraViewType.Perspective, 60, 10))
|
||||
.Button("Cross Track Point", () => CrossTrackPoint.GenerateElement("New Cross Track Point", Guid.NewGuid(), new List<string>(), true, this, new FlexibleInt(), new FlexibleFloat()))
|
||||
.Build();
|
||||
|
||||
var generateEnvironment = container.GenerateSubcontainer(3);
|
||||
var environmentObjectButton = inspector.GenerateButton(this, generateEnvironment, "Environment Object",
|
||||
() => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(),
|
||||
true, this));
|
||||
var timeEffectsCollectionButton = inspector.GenerateButton(this, generateEnvironment, "Time Effects Collection",
|
||||
() => TimeEffectsCollection.GenerateElement("New Time Effects Collection", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 0));
|
||||
var generateParticleEmitterButton = inspector.GenerateButton(this, generateEnvironment, "Generate Particle Emitter", () =>
|
||||
{
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero);
|
||||
});
|
||||
|
||||
var generateTools = container.GenerateSubcontainer(1);
|
||||
inspector.GenerateButton(this, generateTools, "Time Shift Tool", () =>
|
||||
{
|
||||
GeneralSecondaryWindow timeShiftWindow = UnityEngine.Object.Instantiate(
|
||||
EditorManager.instance.basePrefabs.generalSecondaryWindow,
|
||||
EditorManager.instance.uiManager.WindowsCanvas.GetComponent<RectTransform>())
|
||||
.GetComponent<GeneralSecondaryWindow>();
|
||||
|
||||
timeShiftWindow.Initialize("Time Shift Tool");
|
||||
var windowContainer = timeShiftWindow.GenerateContainer("Settings");
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Generate Elements", sectionOrder: 15)
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate Notes", sectionOrder: 20)
|
||||
.Button("Tap", () => Tap.GenerateElement("New Tap", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Stay", () => Stay.GenerateElement("New Stay", Guid.NewGuid(), new List<string>(), true, this, 0f))
|
||||
.Button("Hold", () => Hold.GenerateElement("New Hold", Guid.NewGuid(), new List<string>(), true, this, 0f, 1f))
|
||||
.Button("Flick", () => Flick.GenerateElement("New Flick", Guid.NewGuid(), new List<string>(), true, this, 0f, new List<Vector2>()))
|
||||
.Section("Generate Environment", sectionOrder: 30)
|
||||
.Button("Environment Object", () => TemporaryObject.GenerateElement("New Environment Object", Guid.NewGuid(), new List<string>(), true, this))
|
||||
.Button("Time Effects Collection", () => TimeEffectsCollection.GenerateElement("New Time Effects Collection", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 0))
|
||||
.Button("Particle Emitter", () =>
|
||||
{
|
||||
ParticleEmitter.GenerateElement("New Particle Emitter", Guid.NewGuid(), new List<string>(), true,
|
||||
this, "", "", false, 0, 1, ParticleSystemSimulationSpace.World,
|
||||
10, 5, 1, 1, true, Vector3.zero);
|
||||
})
|
||||
|
||||
var subBase = windowContainer.GenerateSubcontainer(3);
|
||||
var affectNoteToggle = timeShiftWindow.GenerateToggle(subBase, "Affect Notes", true);
|
||||
var offsetInput = timeShiftWindow.GenerateInputField(subBase, "Time Offset (seconds)", "0");
|
||||
.Section("Tools", sectionOrder: 40)
|
||||
.Button("Time Shift Tool", () =>
|
||||
{
|
||||
GeneralSecondaryWindow timeShiftWindow = UnityEngine.Object.Instantiate(
|
||||
EditorManager.instance.basePrefabs.generalSecondaryWindow,
|
||||
EditorManager.instance.uiManager.WindowsCanvas.GetComponent<RectTransform>())
|
||||
.GetComponent<GeneralSecondaryWindow>();
|
||||
|
||||
var btnBase = windowContainer.GenerateSubcontainer(2);
|
||||
timeShiftWindow.GenerateButton(btnBase, "Apply", () =>
|
||||
{
|
||||
if (float.TryParse(offsetInput.inputField.text, out float offset))
|
||||
{
|
||||
ApplyTimeShiftRecursive(affectNoteToggle.toggle.isOn, offset);
|
||||
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
|
||||
LogWindow.Log($"Time shifted by {offset}.", Color.green);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWindow.Log("Invalid number format!", Color.red);
|
||||
}
|
||||
});
|
||||
timeShiftWindow.GenerateButton(btnBase, "Cancel", () =>
|
||||
{
|
||||
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
|
||||
});
|
||||
});
|
||||
timeShiftWindow.Initialize("Time Shift Tool");
|
||||
var windowContainer = timeShiftWindow.GenerateContainer("Settings");
|
||||
|
||||
var subBase = windowContainer.GenerateSubcontainer(3);
|
||||
var affectNoteToggle = timeShiftWindow.GenerateToggle(subBase, "Affect Notes", true);
|
||||
var offsetInput = timeShiftWindow.GenerateInputField(subBase, "Time Offset (seconds)", "0");
|
||||
|
||||
var btnBase = windowContainer.GenerateSubcontainer(2);
|
||||
timeShiftWindow.GenerateButton(btnBase, "Apply", () =>
|
||||
{
|
||||
if (float.TryParse(offsetInput.inputField.text, out float offset))
|
||||
{
|
||||
ApplyTimeShiftRecursive(affectNoteToggle.toggle.isOn, offset);
|
||||
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
|
||||
LogWindow.Log($"Time shifted by {offset}.", Color.green);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWindow.Log("Invalid number format!", Color.red);
|
||||
}
|
||||
});
|
||||
timeShiftWindow.GenerateButton(btnBase, "Cancel", () =>
|
||||
{
|
||||
UnityEngine.Object.Destroy(timeShiftWindow.gameObject);
|
||||
});
|
||||
})
|
||||
.Span(3)
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -18,12 +18,13 @@ namespace Ichni.RhythmGame
|
||||
#region [绘制编辑器面板] Inspector Setup
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Settings");
|
||||
var settingsSubcontainer = container.GenerateSubcontainer(3);
|
||||
var farClipRangeButton = inspector.GenerateInputField(this, settingsSubcontainer, "Far Clip Range",
|
||||
nameof(farClipRange)).AddListenerFunction(ApplyExtension);
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Settings")
|
||||
.InputField(nameof(farClipRange), "Far Clip Range")
|
||||
.OnChanged(ApplyExtension)
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -18,21 +18,22 @@ namespace Ichni.RhythmGame
|
||||
#region [绘制编辑器面板] Inspector Setup
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
base.SetUpInspector();
|
||||
var container = inspector.GenerateContainer("Generate");
|
||||
StandardInspectionElement.GenerateForTransform(this, container); //关于有Transform的元素
|
||||
|
||||
var generateAnimation = container.GenerateSubcontainer(3);
|
||||
var fovAnimationButton = inspector.GenerateButton(this, generateAnimation, "Field of View",
|
||||
() => CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
|
||||
new List<string>(), true, this, new FlexibleFloat(new List<AnimatedFloat>
|
||||
{
|
||||
new AnimatedFloat(0f, 1f, 60f, 60f, AnimationCurveType.Linear)
|
||||
})));
|
||||
var extensionButton = inspector.GenerateButton(this, generateAnimation, "Extension",
|
||||
() => GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 1000f));
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Generate Elements")
|
||||
.Preset(InspectorBuilder.TransformPreset)
|
||||
.Section("Generate")
|
||||
.Button("Field of View", () =>
|
||||
CameraFieldOfView.GenerateElement("New Field of View", Guid.NewGuid(),
|
||||
new List<string>(), true, this, new FlexibleFloat(new List<AnimatedFloat>
|
||||
{
|
||||
new AnimatedFloat(0f, 1f, 60f, 60f, AnimationCurveType.Linear)
|
||||
})))
|
||||
.Button("Extension", () =>
|
||||
GameCameraExtension.GenerateElement("New Extension", Guid.NewGuid(),
|
||||
new List<string>(), true, this, 1000f))
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -101,41 +101,31 @@ namespace Ichni.RhythmGame
|
||||
public virtual void SetUpInspector()
|
||||
{
|
||||
ScanAndAddEnableTypes();
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Element Info");
|
||||
|
||||
var info = container.GenerateSubcontainer(3);
|
||||
var nameInputField = inspector.GenerateInputField(this, info, GetType().Name + "'s Name", nameof(elementName));
|
||||
var guidText = inspector.GenerateParameterText(this, info, "Element GUID", nameof(elementGuid));
|
||||
var tagsListButton = inspector.GenerateButton(this, info, "Tags List", () =>
|
||||
{
|
||||
inspector.GenerateCompositeParameterWindow(this, "Tags List", nameof(tags)).SetAsStringList();
|
||||
});
|
||||
|
||||
if (enableTypes != null && enableTypes.Count > 0)
|
||||
{
|
||||
var elcontainer = inspector.GenerateContainer("Enable Children Display");
|
||||
var enableTypeContainer = elcontainer.GenerateSubcontainer(3);
|
||||
var type = enableTypes.GetType().GetGenericArguments()[0];
|
||||
int elcount = 0;
|
||||
for (int idx = 0; idx < enableTypes.Count; idx++)
|
||||
{
|
||||
elcount++;
|
||||
if (elcount > 3)
|
||||
// Element Info
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Element Info", sectionOrder: 0)
|
||||
.InputField(nameof(elementName), GetType().Name + "'s Name")
|
||||
.ParameterText(nameof(elementGuid), "Element GUID")
|
||||
.Button("Tags List", () =>
|
||||
{
|
||||
elcount = 0;
|
||||
enableTypeContainer = elcontainer.GenerateSubcontainer(3);
|
||||
}
|
||||
var et = enableTypes[idx];
|
||||
inspector.GenerateToggle(
|
||||
et,
|
||||
enableTypeContainer,
|
||||
et.type.Name,
|
||||
nameof(et.enable)
|
||||
);
|
||||
}
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
insp.GenerateCompositeParameterWindow(this, "Tags List", nameof(tags)).SetAsStringList();
|
||||
})
|
||||
.Build();
|
||||
|
||||
// Enable Children Display — 每个 Toggle 绑定不同 EnableType 实例
|
||||
if (enableTypes is { Count: > 0 })
|
||||
{
|
||||
var enableBuilder = InspectorBuilder.For(this)
|
||||
.Section("Enable Children Display", sectionOrder: 1);
|
||||
enableBuilder.ForEach(enableTypes, (b, et, i) =>
|
||||
{
|
||||
b.Toggle(nameof(EnableType.enable), et.type.Name).BoundTo(et);
|
||||
});
|
||||
enableBuilder.Build();
|
||||
}
|
||||
|
||||
|
||||
foreach (var submodule in submoduleList)
|
||||
{
|
||||
submodule.SetUpInspector();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor; // 仅限于在Editor中处理Inspector
|
||||
using Ichni.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public partial class TemporaryObject // Editor UI Setup Partial
|
||||
public partial class TemporaryObject
|
||||
{
|
||||
public List<string> themeBundleList;
|
||||
public List<string> objectNameList;
|
||||
@@ -13,42 +13,30 @@ namespace Ichni.RhythmGame
|
||||
#region [Inspector面版定制] Override Inspector UI Setup
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Temporary Object");
|
||||
|
||||
// 生成实体
|
||||
var generate = container.GenerateSubcontainer(3);
|
||||
var themeBundleDropdown =
|
||||
inspector.GenerateDropdown(this, generate, "Theme Bundle", themeBundleList, nameof(themeBundleName))
|
||||
.AddListenerFunction(() => inspectorMain.SetInspector(this));
|
||||
|
||||
if (themeBundleName != String.Empty && ThemeBundleManager.instance.TryGetThemeBundle(themeBundleName, out ThemeBundle themeBundle))
|
||||
{
|
||||
objectNameList = themeBundle.assetList_GameObject.ConvertAll(x => x.name);
|
||||
var objectNameDropdown =
|
||||
inspector.GenerateDropdown(this, generate, "Object Name", objectNameList, nameof(objectName))
|
||||
.AddListenerFunction(() => inspectorMain.SetInspector(this));
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectNameDropdown =
|
||||
inspector.GenerateDropdown(this, generate, "Object Name", new List<string>(), nameof(objectName));
|
||||
objectNameDropdown.dropdown.interactable = false;
|
||||
} // 如果没有选择主题包,则物体名称下拉框不可用
|
||||
bool hasThemeBundle = themeBundleName != String.Empty;
|
||||
ThemeBundle themeBundle = null;
|
||||
if (hasThemeBundle)
|
||||
hasThemeBundle = ThemeBundleManager.instance.TryGetThemeBundle(themeBundleName, out themeBundle);
|
||||
objectNameList = hasThemeBundle ? themeBundle.assetList_GameObject.ConvertAll(x => x.name) : new List<string>();
|
||||
|
||||
var generateButton = inspector.GenerateButton(this, generate, "Generate", () =>
|
||||
{
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(this);
|
||||
inspectorMain.ClearInspector();
|
||||
SubstantialObject.GenerateElement(elementName, elementGuid, tags, true, themeBundleName, objectName, parentElement);
|
||||
});
|
||||
|
||||
if (themeBundleName == String.Empty || objectName == String.Empty)
|
||||
{
|
||||
generateButton.button.interactable = false;
|
||||
}
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Temporary Object")
|
||||
.Dropdown(nameof(themeBundleName), themeBundleList, "Theme Bundle")
|
||||
.OnChanged(() => inspectorMain.SetInspector(this))
|
||||
.Dropdown(nameof(objectName), objectNameList, "Object Name")
|
||||
.EnabledIf(() => hasThemeBundle)
|
||||
.OnChanged(() => inspectorMain.SetInspector(this))
|
||||
.Button("Generate", () =>
|
||||
{
|
||||
EditorManager.instance.operationManager.CopyPasteDeleteModule.DeleteElement(this);
|
||||
inspectorMain.ClearInspector();
|
||||
SubstantialObject.GenerateElement(elementName, elementGuid, tags, true,
|
||||
themeBundleName, objectName, parentElement);
|
||||
})
|
||||
.EnabledIf(() => themeBundleName != String.Empty && objectName != String.Empty)
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -16,24 +16,18 @@ namespace Ichni.RhythmGame
|
||||
#region [绘制编辑器面板] Inspector Setup
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Variables Container");
|
||||
var subcontainer = container.GenerateSubcontainer(3);
|
||||
|
||||
var originalVariablesButton = inspector.GenerateButton(this, subcontainer, "Original Variables", () =>
|
||||
{
|
||||
var ov =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Original Variables List", nameof(originalVariables))
|
||||
.SetAsStringIntDictionary()
|
||||
.AddListenerFunction(RevertAllVariables);
|
||||
});
|
||||
|
||||
var currentVariablesButton = inspector.GenerateButton(this, subcontainer, "Current Variables", () =>
|
||||
{
|
||||
var cv =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Current Variables List", nameof(currentVariables))
|
||||
.SetAsStringIntDictionary();
|
||||
});
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Variables Container")
|
||||
.Button("Original Variables", () =>
|
||||
insp.GenerateCompositeParameterWindow(this, "Original Variables List", nameof(originalVariables))
|
||||
.SetAsStringIntDictionary()
|
||||
.AddListenerFunction(RevertAllVariables))
|
||||
.Button("Current Variables", () =>
|
||||
insp.GenerateCompositeParameterWindow(this, "Current Variables List", nameof(currentVariables))
|
||||
.SetAsStringIntDictionary())
|
||||
.Build();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,17 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Bloom Shake");
|
||||
var effectSettings = container.GenerateSubcontainer(3);
|
||||
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Bloom Time", nameof(effectTime));
|
||||
var bloomPeakField = inspector.GenerateInputField(this, effectSettings, "Bloom Peak", nameof(peak));
|
||||
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
|
||||
{
|
||||
var intensityCurveWindow =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
|
||||
});
|
||||
SetRemove(effectSettings);
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Bloom Shake")
|
||||
.InputField(nameof(effectTime), "Bloom Time")
|
||||
.InputField(nameof(peak), "Bloom Peak")
|
||||
.Button("Intensity Curve", () => insp.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve())
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,19 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Camera Tilt");
|
||||
var subcontainer1 = container.GenerateSubcontainer(3);
|
||||
var durationField = inspector.GenerateInputField(this, subcontainer1, "Duration", nameof(effectTime));
|
||||
var curveButton = inspector.GenerateButton(this, subcontainer1, "Offset Curve", () =>
|
||||
{
|
||||
var intensityCurveWindow =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Offset Curve", nameof(offsetCurve)).SetAsCustomCurve();
|
||||
});
|
||||
var subcontainer2 = container.GenerateSubcontainer(1);
|
||||
var offsetPeakField = inspector.GenerateVector3InputField(this, subcontainer2, "Offset Value", nameof(offsetValue));
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
SetRemove(subcontainer2);
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Camera Offset")
|
||||
.InputField(nameof(effectTime), "Duration")
|
||||
.Button("Offset Curve", () => insp.GenerateCompositeParameterWindow(this, "Offset Curve", nameof(offsetCurve)).SetAsCustomCurve())
|
||||
.Vector3Field(nameof(offsetValue), "Offset Value")
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,15 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Camera Shake");
|
||||
var effectSettings = container.GenerateSubcontainer(3);
|
||||
var durationInputField = inspector.GenerateInputField(this, effectSettings, "Effect Time", nameof(effectTime));
|
||||
var frequencyInputField = inspector.GenerateInputField(this, effectSettings, "Frequency", nameof(frequency));
|
||||
var amplitudeXInputField = inspector.GenerateInputField(this, effectSettings, "Amplitude X", nameof(amplitudeX));
|
||||
var amplitudeYInputField = inspector.GenerateInputField(this, effectSettings, "Amplitude Y", nameof(amplitudeY));
|
||||
var amplitudeZInputField = inspector.GenerateInputField(this, effectSettings, "Amplitude Z", nameof(amplitudeZ));
|
||||
SetRemove(effectSettings);
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Camera Shake")
|
||||
.InputField(nameof(effectTime), "Effect Time")
|
||||
.InputField(nameof(frequency), "Frequency")
|
||||
.InputField(nameof(amplitudeX), "Amplitude X")
|
||||
.InputField(nameof(amplitudeY), "Amplitude Y")
|
||||
.InputField(nameof(amplitudeZ), "Amplitude Z")
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,20 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Camera Tilt");
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var subcontainer1 = container.GenerateSubcontainer(3);
|
||||
var durationField = inspector.GenerateInputField(this, subcontainer1, "Duration", nameof(effectTime));
|
||||
var tiltCurveButton = inspector.GenerateButton(this, subcontainer1, "Tilt Curve", () =>
|
||||
{
|
||||
var intensityCurveWindow =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Tilt Curve", nameof(tiltCurve)).SetAsCustomCurve();
|
||||
});
|
||||
|
||||
var subcontainer2 = container.GenerateSubcontainer(1);
|
||||
var tiltValueField = inspector.GenerateVector3InputField(this, subcontainer2, "Tilt Value", nameof(tiltValue));
|
||||
SetRemove(subcontainer2);
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Camera Tilt")
|
||||
.InputField(nameof(effectTime), "Duration")
|
||||
.Button("Tilt Curve", () => insp.GenerateCompositeParameterWindow(this, "Tilt Curve", nameof(tiltCurve)).SetAsCustomCurve())
|
||||
.Vector3Field(nameof(tiltValue), "Tilt Value")
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,17 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Camera Zoom");
|
||||
var effectSettings = container.GenerateSubcontainer(3);
|
||||
var zoomDurationInputField = inspector.GenerateInputField(this, effectSettings, "Zoom Duration", nameof(effectTime));
|
||||
var relativeZoomInputField = inspector.GenerateInputField(this, effectSettings, "Relative Zoom", nameof(relativeZoom));
|
||||
var zoomCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
|
||||
{
|
||||
var zoomCurveWindow =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(zoomCurve)).SetAsCustomCurve();
|
||||
});
|
||||
SetRemove(effectSettings);
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Camera Zoom")
|
||||
.InputField(nameof(effectTime), "Zoom Duration")
|
||||
.InputField(nameof(relativeZoom), "Relative Zoom")
|
||||
.Button("Intensity Curve", () => insp.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(zoomCurve)).SetAsCustomCurve())
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Ichni.Editor;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
@@ -9,17 +6,15 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
var container = inspector.GenerateContainer("Chromatic Aberration");
|
||||
var effectSettings = container.GenerateSubcontainer(3);
|
||||
var effectTimeField = inspector.GenerateInputField(this, effectSettings, "Duration", nameof(effectTime));
|
||||
var bloomPeakField = inspector.GenerateInputField(this, effectSettings, "Peak Value", nameof(peak));
|
||||
var intensityCurveButton = inspector.GenerateButton(this, effectSettings, "Intensity Curve", () =>
|
||||
{
|
||||
var intensityCurveWindow =
|
||||
inspector.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve();
|
||||
});
|
||||
SetRemove(effectSettings);
|
||||
IHaveInspection insp = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Chromatic Aberration")
|
||||
.InputField(nameof(effectTime), "Duration")
|
||||
.InputField(nameof(peak), "Peak Value")
|
||||
.Button("Intensity Curve", () => insp.GenerateCompositeParameterWindow(this, "Intensity Curve", nameof(intensityCurve)).SetAsCustomCurve())
|
||||
.Button("Remove", () => { nowEffectState = EffectState.Before; AccommodatingList.Remove(this); EditorManager.instance.uiManager.inspector.SetInspector(attachedGameElement); })
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,37 +11,40 @@ namespace Ichni.RhythmGame
|
||||
{
|
||||
public override void SetUpInspector()
|
||||
{
|
||||
IHaveInspection inspector = EditorManager.instance.uiManager.inspector;
|
||||
Inspector inspectorMain = EditorManager.instance.uiManager.inspector;
|
||||
|
||||
var container = inspector.GenerateContainer("Enable Control");
|
||||
var effectSettings = container.GenerateSubcontainer(3);
|
||||
var connectedGameElementInputField = inspector.GenerateInputField(effectSettings, "Game Element Name");
|
||||
var connectGameElementButton = inspector.GenerateButton(this, effectSettings, "Connect Game Element", () =>
|
||||
{
|
||||
connectedGameElement = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.First(e => e.elementName == connectedGameElementInputField.GetValue<string>());
|
||||
var nameRef = new ElementRef<DynamicUIInputField>();
|
||||
|
||||
if (connectedGameElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.red);
|
||||
}
|
||||
|
||||
inspectorMain.SetInspector(connectedGameElement);
|
||||
});
|
||||
|
||||
string ShowConnection() => connectedGameElement == null ? "No Game Element Connected" : "Connected With: " + connectedGameElement.elementName;
|
||||
var connectHintText = inspector.GenerateHintText(this, effectSettings, ShowConnection);
|
||||
|
||||
var connectedVariableNameInputField = inspector.GenerateInputField(this, effectSettings, "Connected Variable Name", nameof(connectedVariableName));
|
||||
var enableValueInputField = inspector.GenerateInputField(this, effectSettings, "Enable Value", nameof(enableValue));
|
||||
|
||||
// 自定义表达式暂时不可用
|
||||
var useExpressionToggle = inspector.GenerateToggle(this, effectSettings, "Use Expression", nameof(useExpression));
|
||||
useExpressionToggle.toggle.interactable = false;
|
||||
var expressionInputField = inspector.GenerateInputField(this, effectSettings, "Expression", nameof(expression));
|
||||
expressionInputField.inputField.interactable = false;
|
||||
SetRemove(effectSettings);
|
||||
InspectorBuilder.For(this)
|
||||
.Section("Enable Control")
|
||||
.UnboundInputField("Game Element Name").WithRef(nameRef)
|
||||
.Button("Connect Game Element", () =>
|
||||
{
|
||||
connectedGameElement = EditorManager.instance.beatmapContainer.gameElementList
|
||||
.FirstOrDefault(e => e.elementName == nameRef.Value?.GetValue<string>());
|
||||
if (connectedGameElement == null)
|
||||
{
|
||||
LogWindow.Log("Game Element not found.", Color.red);
|
||||
return;
|
||||
}
|
||||
inspectorMain.SetInspector(connectedGameElement);
|
||||
})
|
||||
.HintText(() => connectedGameElement == null
|
||||
? "No Game Element Connected"
|
||||
: "Connected With: " + connectedGameElement.elementName)
|
||||
.InputField(nameof(connectedVariableName), "Connected Variable Name")
|
||||
.InputField(nameof(enableValue), "Enable Value")
|
||||
.Toggle(nameof(useExpression), "Use Expression")
|
||||
.EnabledIf(() => false)
|
||||
.InputField(nameof(expression), "Expression")
|
||||
.EnabledIf(() => false)
|
||||
.Button("Remove", () =>
|
||||
{
|
||||
nowEffectState = EffectState.Before;
|
||||
AccommodatingList.Remove(this);
|
||||
inspectorMain.SetInspector(attachedGameElement);
|
||||
})
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user