added localization packages, generated meta, adresables
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 175cafb710462ef489cbf56cb46c97d5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3459a30abd1a4e979488e906febc27e7
|
||||
timeCreated: 1707714315
|
||||
@@ -0,0 +1,29 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
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: 2fc91909e6444cb29aacb664f2098c7e, type: 3}
|
||||
m_Name: OdinLocalizationConfig
|
||||
m_EditorClassIdentifier:
|
||||
recordUndosForAssetTableEntries: 1
|
||||
assetRowHeight: 128
|
||||
useSyntaxHighlighter: 1
|
||||
placeholderColor:
|
||||
lightColor: {r: 0.743147, g: 0.9433962, b: 0.9242815, a: 1}
|
||||
darkColor: {r: 0, g: 0.5882353, b: 0.5333334, a: 1}
|
||||
selectorColor:
|
||||
lightColor: {r: 1, g: 0.7727525, b: 0.3632075, a: 1}
|
||||
darkColor: {r: 1, g: 0.6470588, b: 0, a: 1}
|
||||
formatterColor:
|
||||
lightColor: {r: 0.9921569, g: 0.9855571, b: 0.8823529, a: 1}
|
||||
darkColor: {r: 0.9607843, g: 0.9607843, b: 0.8627451, a: 1}
|
||||
scrollSpeed: 24
|
||||
invertMouseDragNavigation: 1
|
||||
mouseDragSpeed: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c09625914af7d2d4e92c3653d5f15bd7
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,173 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationConfig.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
using Sirenix.Reflection.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Configs
|
||||
{
|
||||
[GlobalConfig("Plugins/Sirenix/Odin Inspector/Modules/Unity.Localization/Editor/Configs")]
|
||||
public class OdinLocalizationConfig : GlobalConfig<OdinLocalizationConfig>
|
||||
{
|
||||
public class ThemeColorDrawer : OdinValueDrawer<ThemeColor>
|
||||
{
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
this.Property.State.Expanded = false;
|
||||
}
|
||||
|
||||
protected override void DrawPropertyLayout(GUIContent label)
|
||||
{
|
||||
SirenixEditorGUI.BeginBox(string.Empty);
|
||||
{
|
||||
SirenixEditorGUI.BeginBoxHeader();
|
||||
{
|
||||
GUILayout_Internal.BeginRow();
|
||||
{
|
||||
GUILayout_Internal.BeginColumn(LayoutSize.Pixels(EditorGUIUtility.labelWidth + 6.0f));
|
||||
{
|
||||
this.Property.State.Expanded = EditorGUILayout.Foldout(this.Property.State.Expanded,
|
||||
$"{label.text} ({(EditorGUIUtility.isProSkin ? "Dark" : "Light")})",
|
||||
true);
|
||||
}
|
||||
GUILayout_Internal.EndColumn();
|
||||
|
||||
GUILayout_Internal.BeginColumn(LayoutSize.Auto);
|
||||
{
|
||||
this.Property.Children[nameof(ThemeColor.Color)].Draw(null);
|
||||
}
|
||||
GUILayout_Internal.EndColumn();
|
||||
}
|
||||
GUILayout_Internal.EndRow();
|
||||
}
|
||||
SirenixEditorGUI.EndBoxHeader();
|
||||
|
||||
bool toggle = this.ValueEntry.ValueState != PropertyValueState.NullReference && this.Property.State.Expanded;
|
||||
|
||||
if (SirenixEditorGUI.BeginFadeGroup(this, toggle))
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
this.Property.Children[nameof(ThemeColor.lightColor)].Draw();
|
||||
GUILayout.Space(3.5f);
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
this.Property.Children[nameof(ThemeColor.darkColor)].Draw();
|
||||
GUILayout.Space(3.5f);
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
SirenixEditorGUI.EndFadeGroup();
|
||||
}
|
||||
SirenixEditorGUI.EndBox();
|
||||
|
||||
if (this.Property.State.Expanded)
|
||||
{
|
||||
GUILayout.Space(4.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ThemeColor
|
||||
{
|
||||
[ShowInInspector]
|
||||
public Color Color
|
||||
{
|
||||
get => EditorGUIUtility.isProSkin ? this.darkColor : this.lightColor;
|
||||
|
||||
set
|
||||
{
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
this.darkColor = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.lightColor = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color lightColor;
|
||||
public Color darkColor;
|
||||
|
||||
public ThemeColor(Color lightColor, Color darkColor)
|
||||
{
|
||||
this.lightColor = lightColor;
|
||||
this.darkColor = darkColor;
|
||||
}
|
||||
|
||||
public static implicit operator Color(ThemeColor color) => color.Color;
|
||||
}
|
||||
|
||||
[ShowInInspector]
|
||||
[BoxGroup("User Interface")]
|
||||
[Range(96, 1024)]
|
||||
public int assetRowHeight = 128;
|
||||
|
||||
[BoxGroup("Syntax Highlighting")]
|
||||
public bool useSyntaxHighlighter = true;
|
||||
|
||||
[EnableIf(nameof(useSyntaxHighlighter))]
|
||||
[BoxGroup("Syntax Highlighting")]
|
||||
public ThemeColor placeholderColor = new ThemeColor(new Color(0.743147f, 0.9433962f, 0.9242815f), new Color(0, 0.5882353f, 0.5333334f));
|
||||
|
||||
[EnableIf(nameof(useSyntaxHighlighter))]
|
||||
[BoxGroup("Syntax Highlighting")]
|
||||
public ThemeColor selectorColor = new ThemeColor(new Color(1.0f, 0.7727525f, 0.3632075f), new Color(1, 0.6470588f, 0));
|
||||
|
||||
[EnableIf(nameof(useSyntaxHighlighter))]
|
||||
[BoxGroup("Syntax Highlighting")]
|
||||
public ThemeColor formatterColor = new ThemeColor(new Color(0.9921569f, 0.9855571f, 0.8823529f), new Color(0.9607843f, 0.9607843f, 0.8627451f));
|
||||
|
||||
[BoxGroup("Navigation")]
|
||||
[Range(1, 1000.0f)]
|
||||
public float scrollSpeed = 24.0f;
|
||||
|
||||
[BoxGroup("Navigation")]
|
||||
public bool invertMouseDragNavigation = true;
|
||||
|
||||
[BoxGroup("Navigation")]
|
||||
[Range(0.5f, 5.0f)]
|
||||
public float mouseDragSpeed = 1.0f;
|
||||
|
||||
[InfoBox("We couldn't find the necessary methods/classes to perform custom undo operations, therefore this option has been disabled and will be considered false even if true.",
|
||||
VisibleIf = "@!OdinLocalizationReflectionValues.HasAPIForCustomUndo")]
|
||||
[EnableIf("@OdinLocalizationReflectionValues.HasAPIForCustomUndo")]
|
||||
[BoxGroup("Undo")]
|
||||
public bool useCustomUndoHandlingForAssetCollections = true;
|
||||
|
||||
[Button(ButtonSizes.Large)]
|
||||
public void Reset()
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("Odin Localization Config", "Are you certain you want to reset your Localization config?", "Yes", "No"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.useCustomUndoHandlingForAssetCollections = OdinLocalizationReflectionValues.HasAPIForCustomUndo;
|
||||
|
||||
this.assetRowHeight = 128;
|
||||
|
||||
this.useSyntaxHighlighter = true;
|
||||
this.placeholderColor = new ThemeColor(new Color(0.743147f, 0.9433962f, 0.9242815f), new Color(0, 0.5882353f, 0.5333334f));
|
||||
this.selectorColor = new ThemeColor(new Color(1.0f, 0.7727525f, 0.3632075f), new Color(1, 0.6470588f, 0));
|
||||
this.formatterColor = new ThemeColor(new Color(0.9921569f, 0.9855571f, 0.8823529f), new Color(0.9607843f, 0.9607843f, 0.8627451f));
|
||||
|
||||
this.scrollSpeed = 24.0f;
|
||||
this.invertMouseDragNavigation = true;
|
||||
this.mouseDragSpeed = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fc91909e6444cb29aacb664f2098c7e
|
||||
timeCreated: 1707714331
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf930ee5d27d4f90ab84f23d337eaaca
|
||||
timeCreated: 1704811167
|
||||
@@ -0,0 +1,993 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="LocalizationMetadata.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Metadata;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class LocalizationMetadata
|
||||
{
|
||||
private object lastTarget;
|
||||
public object Target;
|
||||
private LocalizationTableCollection localizationTableCollection;
|
||||
private SearchField searchField = new SearchField();
|
||||
private string searchTerm;
|
||||
private Vector2 scrollPosition;
|
||||
private IMetadata toBeAdded;
|
||||
private IMetadata toBeRemoved;
|
||||
private Type lastMetadataTypeUnderCursor;
|
||||
private StringBuilder stringBuilder = new StringBuilder();
|
||||
private OdinLocalizationEditorWindow.WindowState windowState;
|
||||
|
||||
private List<Type> tags = new List<Type>
|
||||
{
|
||||
typeof(ExcludeEntryFromExport)
|
||||
};
|
||||
|
||||
private GUIStyle _contentPadding;
|
||||
private GUIStyle ContentPadding =>
|
||||
this._contentPadding = this._contentPadding ?? new GUIStyle
|
||||
{
|
||||
padding = new RectOffset(10, 10, 10, 10)
|
||||
};
|
||||
|
||||
private GUIStyle _platformOverridePadding;
|
||||
|
||||
private GUIStyle PlatformOverridePadding =>
|
||||
this._platformOverridePadding = this._platformOverridePadding ?? new GUIStyle
|
||||
{
|
||||
padding = new RectOffset(10, 20, 10, 10)
|
||||
};
|
||||
|
||||
public LocalizationMetadata(LocalizationTableCollection localizationTableCollection, OdinLocalizationEditorWindow.WindowState windowState)
|
||||
{
|
||||
this.localizationTableCollection = localizationTableCollection;
|
||||
this.windowState = windowState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given metadata to the shared data of the <see cref="LocalizationTableCollection"/>.
|
||||
/// </summary>
|
||||
public void Add(IMetadata metadata)
|
||||
{
|
||||
this.localizationTableCollection.SharedData.Metadata.AddMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given metadata to the given <see cref="LocalizationTable"/>.
|
||||
/// </summary>
|
||||
public void Add(LocalizationTable localizationTable, IMetadata metadata)
|
||||
{
|
||||
localizationTable.AddMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given metadata to the given <see cref="SharedTableData"/>.
|
||||
/// </summary>
|
||||
public void Add(SharedTableData.SharedTableEntry sharedTableEntry, IMetadata metadata)
|
||||
{
|
||||
sharedTableEntry.Metadata.AddMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given metadata to the given <see cref="TableEntry"/>.
|
||||
/// </summary>
|
||||
public void Add(TableEntry tableEntry, IMetadata metadata)
|
||||
{
|
||||
tableEntry.AddMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given metadata from the shared data of the <see cref="LocalizationTableCollection"/>.
|
||||
/// </summary>
|
||||
public void Remove(IMetadata metadata)
|
||||
{
|
||||
this.localizationTableCollection.SharedData.Metadata.RemoveMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given metadata from the given <see cref="LocalizationTable"/>.
|
||||
/// </summary>
|
||||
public void Remove(LocalizationTable localizationTable, IMetadata metadata)
|
||||
{
|
||||
localizationTable.RemoveMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given metadata from the given <see cref="SharedTableData"/>.
|
||||
/// </summary>
|
||||
public void Remove(SharedTableData.SharedTableEntry sharedTableEntry, IMetadata metadata)
|
||||
{
|
||||
sharedTableEntry.Metadata.RemoveMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the given metadata from the given <see cref="TableEntry"/>.
|
||||
/// </summary>
|
||||
public void Remove(TableEntry tableEntry, IMetadata metadata)
|
||||
{
|
||||
tableEntry.RemoveMetadata(metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the metadata for the given <see cref="LocalizationTableCollection"/>
|
||||
/// </summary>
|
||||
public float Draw(Rect rect)
|
||||
{
|
||||
var minWidth = 0f;
|
||||
if (this.Target == null) return minWidth;
|
||||
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
{
|
||||
if (this.toBeAdded != null)
|
||||
{
|
||||
switch (this.Target)
|
||||
{
|
||||
case LocalizationTable localizationTable:
|
||||
Undo.RecordObject(this.localizationTableCollection, "Localization Tables Metadata Added");
|
||||
this.Add(localizationTable, this.toBeAdded);
|
||||
break;
|
||||
case SharedTableData.SharedTableEntry sharedTableEntry:
|
||||
Undo.RecordObject(this.localizationTableCollection.SharedData, "Localization Tables Metadata Added");
|
||||
this.Add(sharedTableEntry, this.toBeAdded);
|
||||
break;
|
||||
case TableEntry tableEntry:
|
||||
Undo.RecordObject(tableEntry.Table, "Localization Tables Metadata Added");
|
||||
this.Add(tableEntry, this.toBeAdded);
|
||||
break;
|
||||
default:
|
||||
Undo.RecordObject(this.localizationTableCollection.SharedData, "Localization Tables Metadata Added");
|
||||
this.Add(this.toBeAdded);
|
||||
break;
|
||||
}
|
||||
|
||||
this.toBeAdded = null;
|
||||
this.windowState.Dispose();
|
||||
}
|
||||
|
||||
if (this.toBeRemoved != null)
|
||||
{
|
||||
switch (this.Target)
|
||||
{
|
||||
case LocalizationTable localizationTable:
|
||||
Undo.RecordObject(this.localizationTableCollection, "Localization Tables Metadata Removed");
|
||||
this.Remove(localizationTable, this.toBeRemoved);
|
||||
break;
|
||||
case SharedTableData.SharedTableEntry sharedTableEntry:
|
||||
Undo.RecordObject(this.localizationTableCollection.SharedData, "Localization Tables Metadata Removed");
|
||||
this.Remove(sharedTableEntry, this.toBeRemoved);
|
||||
break;
|
||||
case TableEntry tableEntry:
|
||||
Undo.RecordObject(tableEntry.Table, "Localization Tables Metadata Removed");
|
||||
this.Remove(tableEntry, this.toBeRemoved);
|
||||
break;
|
||||
default:
|
||||
Undo.RecordObject(this.localizationTableCollection.SharedData, "Localization Tables Metadata Removed");
|
||||
this.Remove(this.toBeRemoved);
|
||||
break;
|
||||
}
|
||||
|
||||
this.toBeRemoved = null;
|
||||
this.windowState.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.windowState.MetadataTree == null || this.lastTarget != this.Target)
|
||||
{
|
||||
this.windowState.MetadataTree?.Dispose();
|
||||
|
||||
switch (this.Target)
|
||||
{
|
||||
case LocalizationTable localizationTable:
|
||||
this.windowState.MetadataTree = PropertyTree.Create(localizationTable);
|
||||
break;
|
||||
case SharedTableData.SharedTableEntry sharedTableEntry:
|
||||
this.windowState.MetadataTree = PropertyTree.Create(sharedTableEntry);
|
||||
break;
|
||||
case TableEntry tableEntry:
|
||||
{
|
||||
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
var entryData = typeof(TableEntry).GetProperty("Data", bindingFlags).GetValue(tableEntry);
|
||||
this.windowState.MetadataTree = PropertyTree.Create(entryData);
|
||||
break;
|
||||
}
|
||||
case LocalizationTableCollection localizationTableCollection:
|
||||
this.windowState.MetadataTree = PropertyTree.Create(localizationTableCollection.SharedData);
|
||||
break;
|
||||
}
|
||||
|
||||
this.lastTarget = this.Target;
|
||||
}
|
||||
|
||||
var metadataCollection = this.windowState.MetadataTree.RootProperty.Children["m_Metadata"];
|
||||
var metadataEntries = metadataCollection.Children["m_Items"].Children.ToList();
|
||||
|
||||
metadataEntries = metadataEntries
|
||||
.Where(entry => !entry.Attributes.HasAttribute<HideInInspector>())
|
||||
.OrderBy(entry => !this.tags.Contains(entry.ValueEntry.TypeOfValue))
|
||||
.ThenBy(entry => entry.Name)
|
||||
.ToList();
|
||||
|
||||
this.windowState.MetadataTree.BeginDraw(false);
|
||||
switch (this.Target)
|
||||
{
|
||||
case LocalizationTable localizationTable:
|
||||
minWidth = this.Draw(rect, localizationTable, "Table", metadataEntries, m => this.Add(localizationTable, m), m => this.Remove(localizationTable, m), () => this.OpenMetadataSelector(localizationTable));
|
||||
break;
|
||||
case SharedTableData.SharedTableEntry sharedTableEntry:
|
||||
minWidth = this.Draw(rect, this.localizationTableCollection.SharedData, "Shared Entry", metadataEntries, m => this.Add(sharedTableEntry, m), m => this.Remove(sharedTableEntry, m), () => this.OpenMetadataSelector(sharedTableEntry));
|
||||
break;
|
||||
case TableEntry tableEntry:
|
||||
minWidth = this.Draw(rect, tableEntry.Table, "Entry", metadataEntries, m => this.Add(tableEntry, m), m => this.Remove(tableEntry, m), () => this.OpenMetadataSelector(tableEntry));
|
||||
break;
|
||||
default:
|
||||
minWidth = this.Draw(rect, this.localizationTableCollection.SharedData, "Shared Table", metadataEntries, m => this.Add(m), m => this.Remove(m), () => this.OpenMetadataSelector(this.localizationTableCollection));
|
||||
break;
|
||||
}
|
||||
this.windowState.MetadataTree.EndDraw();
|
||||
|
||||
return minWidth;
|
||||
}
|
||||
|
||||
private float Draw(Rect rect, UnityEngine.Object target, string title, List<InspectorProperty> metadataEntries, Action<IMetadata> add, Action<IMetadata> remove, Action openMetadataSelector)
|
||||
{
|
||||
const int headerHeight = 22;
|
||||
const int addButtonAreaHeight = 40;
|
||||
|
||||
EditorGUIUtility.labelWidth = 0f;
|
||||
|
||||
// We only want to process events if the user's mouse is currently
|
||||
// in the metadata panel so we grab some information for later.
|
||||
var metadataPanelHasFocus = Event.current.IsMouseOver(rect);
|
||||
var holdingControl = Event.current.control && metadataPanelHasFocus;
|
||||
var holdingAlt = Event.current.alt && metadataPanelHasFocus;
|
||||
|
||||
if (Event.current.OnKeyUp(KeyCode.LeftAlt))
|
||||
{
|
||||
this.lastMetadataTypeUnderCursor = null;
|
||||
}
|
||||
|
||||
var searchAreaRect = rect.TakeFromTop(32);
|
||||
EditorGUI.DrawRect(searchAreaRect.AlignBottom(1), SirenixGUIStyles.BorderColor);
|
||||
|
||||
// Draw search field.
|
||||
if (searchAreaRect.width > 125)
|
||||
{
|
||||
var titleWidth = SirenixGUIStyles.LabelCentered.CalcWidth(title) + 13;
|
||||
var titleRect = searchAreaRect.AlignRight(titleWidth);
|
||||
EditorGUI.DrawRect(titleRect.TakeFromLeft(1), SirenixGUIStyles.BorderColor);
|
||||
this.searchTerm = this.searchField.Draw(searchAreaRect.SubXMax(titleWidth).Padding(6), this.searchTerm,
|
||||
"Search for metadata...");
|
||||
GUI.Label(titleRect, title, SirenixGUIStyles.LabelCentered);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.Label(searchAreaRect, title, SirenixGUIStyles.LabelCentered);
|
||||
}
|
||||
|
||||
var filteredMetadataEntries = string.IsNullOrWhiteSpace(this.searchTerm)
|
||||
? metadataEntries.ToList()
|
||||
: metadataEntries.Where(metadataEntry =>
|
||||
{
|
||||
if (FuzzySearch.Contains(this.searchTerm, metadataEntry.Info.TypeOfOwner.Name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FuzzySearch.Contains(this.searchTerm, metadataEntry.ValueEntry?.WeakSmartValue?.ToString()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var child in metadataEntry.Children.Recurse())
|
||||
{
|
||||
if (FuzzySearch.Contains(this.searchTerm, child.Name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FuzzySearch.Contains(this.searchTerm, child.ValueEntry?.WeakSmartValue?.ToString()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}).ToList();
|
||||
|
||||
var metadataViewHeight = rect.height - addButtonAreaHeight;
|
||||
GUILayout.BeginArea(rect.AlignTop(metadataViewHeight));
|
||||
this.scrollPosition = EditorGUILayout.BeginScrollView(this.scrollPosition, GUIStyle.none, GUI.skin.verticalScrollbar);
|
||||
GUIHelper.BeginLayoutMeasuring();
|
||||
{
|
||||
for (var i = 0; i < filteredMetadataEntries.Count; i++)
|
||||
{
|
||||
var metadataEntry = filteredMetadataEntries[i];
|
||||
var metadataHeaderRect = GUILayoutUtility.GetRect(0, headerHeight, GUILayoutOptions.ExpandWidth().ExpandHeight(false));
|
||||
var unchangedMetadataHeaderRect = metadataHeaderRect;
|
||||
|
||||
var genericMenu = new GenericMenu();
|
||||
genericMenu.AddItem(new GUIContent("Delete"), false, () =>
|
||||
{
|
||||
var metadata = (IMetadata)metadataEntry.ValueEntry.WeakSmartValue;
|
||||
this.toBeRemoved = metadata;
|
||||
});
|
||||
|
||||
var isTag = this.tags.Contains(metadataEntry.ValueEntry.TypeOfValue);
|
||||
|
||||
if (!isTag)
|
||||
{
|
||||
genericMenu.AddItem(new GUIContent("Copy"), false, () =>
|
||||
{
|
||||
var metadata = (IMetadata)metadataEntry.ValueEntry.WeakSmartValue;
|
||||
Clipboard.Copy(metadata);
|
||||
});
|
||||
|
||||
if (Clipboard.CanPaste<IMetadata>())
|
||||
genericMenu.AddItem(new GUIContent("Paste"), false, () =>
|
||||
{
|
||||
var metadata = (IMetadata)Clipboard.Paste();
|
||||
this.toBeAdded = metadata;
|
||||
});
|
||||
else
|
||||
genericMenu.AddDisabledItem(new GUIContent("Paste"));
|
||||
|
||||
genericMenu.AddSeparator("");
|
||||
genericMenu.AddItem(new GUIContent($"{(metadataEntry.State.Expanded ? "Collapse" : "Expand")} All (Ctrl-Click)"), false, () =>
|
||||
{
|
||||
var newState = !metadataEntry.State.Expanded;
|
||||
foreach (var entry in filteredMetadataEntries) entry.State.Expanded = newState;
|
||||
});
|
||||
genericMenu.AddItem(new GUIContent($"{(metadataEntry.State.Expanded ? "Collapse" : "Expand")} All Of Same Type (Alt-Click)"), false, () =>
|
||||
{
|
||||
var newState = !metadataEntry.State.Expanded;
|
||||
foreach (var entry in filteredMetadataEntries.Where(m => m.Info.TypeOfOwner == metadataEntry.Info.TypeOfOwner)) entry.State.Expanded = newState;
|
||||
});
|
||||
}
|
||||
|
||||
Color metadataHeaderBackground = new Color(0.243f, 0.243f, 0.243f);
|
||||
|
||||
if (!isTag && holdingControl)
|
||||
{
|
||||
metadataHeaderBackground = new Color(0.278f, 0.278f, 0.278f);
|
||||
|
||||
GUIHelper.RequestRepaint();
|
||||
}
|
||||
else if (!isTag && holdingAlt)
|
||||
{
|
||||
if (Event.current.IsMouseOver(unchangedMetadataHeaderRect))
|
||||
{
|
||||
this.lastMetadataTypeUnderCursor = metadataEntry.ValueEntry.TypeOfValue;
|
||||
GUIHelper.RequestRepaint();
|
||||
}
|
||||
|
||||
metadataHeaderBackground = this.lastMetadataTypeUnderCursor == metadataEntry.ValueEntry.TypeOfValue
|
||||
? new Color(0.278f, 0.278f, 0.278f)
|
||||
: new Color(0.243f, 0.243f, 0.243f);
|
||||
}
|
||||
|
||||
if (Event.current.IsMouseOver(unchangedMetadataHeaderRect))
|
||||
{
|
||||
metadataHeaderBackground = new Color(0.278f, 0.278f, 0.278f);
|
||||
}
|
||||
|
||||
EditorGUI.DrawRect(unchangedMetadataHeaderRect, metadataHeaderBackground);
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
EditorGUI.DrawRect(unchangedMetadataHeaderRect.AlignTop(1), new Color(0.102f, 0.102f, 0.102f));
|
||||
}
|
||||
|
||||
var foldoutTriangleRect = metadataHeaderRect.TakeFromLeft(headerHeight);
|
||||
|
||||
if (!isTag)
|
||||
SdfIcons.DrawIcon(
|
||||
foldoutTriangleRect.Padding(6),
|
||||
metadataEntry.State.Expanded ? SdfIconType.CaretDownFill : SdfIconType.CaretRightFill,
|
||||
new Color(0.443f, 0.443f, 0.443f));
|
||||
|
||||
var iconRect = metadataHeaderRect.TakeFromLeft(headerHeight);
|
||||
SdfIcons.DrawIcon(
|
||||
iconRect.Padding(0, 4, 4, 4),
|
||||
isTag ? SdfIconType.TagFill : SdfIconType.GeoAltFill,
|
||||
new Color(0.933f, 0.933f, 0.933f));
|
||||
|
||||
var contextMenuIconRect = metadataHeaderRect.TakeFromRight(headerHeight);
|
||||
|
||||
SdfIcons.DrawIcon(contextMenuIconRect.Padding(7), SdfIconType.ThreeDotsVertical);
|
||||
|
||||
var niceName = ObjectNames.NicifyVariableName(metadataEntry.ValueEntry.TypeOfValue.GetNiceName());
|
||||
|
||||
if (metadataEntry.Info.TypeOfOwner == typeof(Comment))
|
||||
{
|
||||
var headerLabelWidth = EditorStyles.label.CalcWidth(niceName) + 1;
|
||||
var comment = ((string)metadataEntry.ValueEntry.WeakSmartValue).Split('\n')[0];
|
||||
var hintRect = metadataHeaderRect.AlignRight(metadataHeaderRect.width - headerLabelWidth - 10);
|
||||
|
||||
if (SirenixGUIStyles.RightAlignedGreyMiniLabel.CalcWidth(comment) > hintRect.width)
|
||||
{
|
||||
if (hintRect.width < 30)
|
||||
{
|
||||
comment = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.Label(hintRect.TakeFromLeft(11), "...", SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Label(hintRect, comment, SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
else if (metadataEntry.Info.TypeOfOwner == typeof(PreloadAssetTableMetadata))
|
||||
{
|
||||
var headerLabelWidth = EditorStyles.label.CalcWidth(niceName) + 1;
|
||||
var preloadAssetLabel = ObjectNames.NicifyVariableName(metadataEntry.ValueEntry.WeakSmartValue.ToString());
|
||||
var hintRect = metadataHeaderRect.AlignRight(metadataHeaderRect.width - headerLabelWidth - 10);
|
||||
|
||||
if (SirenixGUIStyles.RightAlignedGreyMiniLabel.CalcWidth(preloadAssetLabel) > hintRect.width)
|
||||
{
|
||||
if (hintRect.width < 30)
|
||||
{
|
||||
preloadAssetLabel = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.Label(hintRect.TakeFromLeft(11), "...", SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Label(hintRect, preloadAssetLabel, SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
else if (metadataEntry.Info.TypeOfOwner == typeof(PlatformOverride))
|
||||
{
|
||||
var platformOverrides = metadataEntry.Children;
|
||||
var headerLabelWidth = EditorStyles.label.CalcWidth(niceName) + 1;
|
||||
var hintRect = metadataHeaderRect.AlignRight(metadataHeaderRect.width - headerLabelWidth - 10);
|
||||
|
||||
this.stringBuilder.Clear();
|
||||
for (var j = 0; j < platformOverrides.Count; j++)
|
||||
{
|
||||
var platformOverrideInspectorProperty = platformOverrides[j];
|
||||
var platform = (RuntimePlatform)platformOverrideInspectorProperty.Children[0].ValueEntry.WeakSmartValue;
|
||||
this.stringBuilder.Append(platform);
|
||||
|
||||
if (j != platformOverrides.Count - 1)
|
||||
{
|
||||
this.stringBuilder.Append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
var platforms = this.stringBuilder.ToString();
|
||||
|
||||
if (SirenixGUIStyles.RightAlignedGreyMiniLabel.CalcWidth(platforms) > hintRect.width)
|
||||
{
|
||||
if (hintRect.width < 30)
|
||||
{
|
||||
GUI.Label(hintRect, $"[{platformOverrides.Count}]", SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
platforms = "";
|
||||
}
|
||||
else if (platformOverrides.Count > 1)
|
||||
{
|
||||
GUI.Label(hintRect.TakeFromLeft(11), "...", SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Label(hintRect, platforms, SirenixGUIStyles.RightAlignedGreyMiniLabel);
|
||||
}
|
||||
|
||||
GUI.Label(metadataHeaderRect, niceName);
|
||||
|
||||
var evt = Event.current;
|
||||
if (evt.OnMouseDown(contextMenuIconRect, 0, false))
|
||||
genericMenu.ShowAsContext();
|
||||
else if (evt.OnMouseDown(unchangedMetadataHeaderRect, 1, false)) genericMenu.ShowAsContext();
|
||||
|
||||
if (metadataEntry.ValueEntry.TypeOfValue == typeof(ExcludeEntryFromExport)) continue;
|
||||
|
||||
if (evt.OnMouseDown(unchangedMetadataHeaderRect, 0, false))
|
||||
{
|
||||
if (holdingControl)
|
||||
{
|
||||
var newState = !metadataEntry.State.Expanded;
|
||||
foreach (var entry in filteredMetadataEntries)
|
||||
{
|
||||
entry.State.Expanded = newState;
|
||||
}
|
||||
}
|
||||
else if (holdingAlt)
|
||||
{
|
||||
var newState = !metadataEntry.State.Expanded;
|
||||
foreach (var entry in filteredMetadataEntries.Where(m => m.ValueEntry.TypeOfValue == this.lastMetadataTypeUnderCursor))
|
||||
{
|
||||
entry.State.Expanded = newState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
metadataEntry.State.Expanded = !metadataEntry.State.Expanded;
|
||||
}
|
||||
|
||||
GUIHelper.RemoveFocusControl();
|
||||
}
|
||||
|
||||
if (SirenixEditorGUI.BeginFadeGroup(metadataEntry, metadataEntry.State.Expanded))
|
||||
{
|
||||
EditorGUI.DrawRect(unchangedMetadataHeaderRect.AlignBottom(1),
|
||||
new Color(0.188f, 0.188f, 0.188f));
|
||||
|
||||
var contentRect = EditorGUILayout.BeginVertical();
|
||||
|
||||
if (metadataEntry.ValueEntry.TypeOfValue == typeof(Comment))
|
||||
{
|
||||
EditorGUILayout.BeginVertical(this.ContentPadding);
|
||||
foreach (var child in metadataEntry.Children)
|
||||
{
|
||||
child.Draw(null);
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
else if (metadataEntry.ValueEntry.TypeOfValue == typeof(PreloadAssetTableMetadata))
|
||||
{
|
||||
EditorGUILayout.BeginVertical(this.ContentPadding);
|
||||
|
||||
var preloadAssetTableMetadata = (PreloadAssetTableMetadata)metadataEntry.ValueEntry.WeakSmartValue;
|
||||
var btnRect = EditorGUILayout.GetControlRect(false);
|
||||
var leftRect = btnRect.Split(0, 2);
|
||||
var mouseOverLeft = Event.current.IsMouseOver(leftRect);
|
||||
var leftActive = mouseOverLeft && Event.current.type == EventType.MouseDown && Event.current.button == 0;
|
||||
var leftOn = preloadAssetTableMetadata.Behaviour == PreloadAssetTableMetadata.PreloadBehaviour.NoPreload;
|
||||
|
||||
var rightRect = btnRect.Split(1, 2);
|
||||
var mouseOverRight = Event.current.IsMouseOver(rightRect);
|
||||
var rightActive = mouseOverRight && Event.current.type == EventType.MouseDown && Event.current.button == 0;
|
||||
var rightOn = preloadAssetTableMetadata.Behaviour == PreloadAssetTableMetadata.PreloadBehaviour.PreloadAll;
|
||||
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
SirenixGUIStyles.ButtonLeft.Draw(leftRect, "No Preload", mouseOverLeft, leftActive, leftOn, false);
|
||||
SirenixGUIStyles.ButtonRight.Draw(rightRect, "Preload All", mouseOverRight, rightActive, rightOn, false);
|
||||
}
|
||||
|
||||
if (Event.current.OnMouseDown(leftRect, 0, false))
|
||||
{
|
||||
preloadAssetTableMetadata.Behaviour = PreloadAssetTableMetadata.PreloadBehaviour.NoPreload;
|
||||
}
|
||||
else if (Event.current.OnMouseDown(rightRect, 0, false))
|
||||
{
|
||||
preloadAssetTableMetadata.Behaviour = PreloadAssetTableMetadata.PreloadBehaviour.PreloadAll;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
else if (metadataEntry.ValueEntry.TypeOfValue == typeof(PlatformOverride))
|
||||
{
|
||||
this.DrawPlatformOverride(metadataEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginVertical(this.ContentPadding);
|
||||
foreach (var child in metadataEntry.Children)
|
||||
{
|
||||
child.Draw();
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
SirenixEditorGUI.EndFadeGroup();
|
||||
}
|
||||
}
|
||||
var measureRect = GUIHelper.EndLayoutMeasuring();
|
||||
EditorGUILayout.EndScrollView();
|
||||
GUILayout.EndArea();
|
||||
|
||||
var pinAddMetadataButton = measureRect.height > metadataViewHeight;
|
||||
rect.TakeFromTop(pinAddMetadataButton ? metadataViewHeight : measureRect.height);
|
||||
|
||||
if (metadataEntries.Count > 1)
|
||||
{
|
||||
EditorGUI.DrawRect(rect.TakeFromTop(1), SirenixGUIStyles.BorderColor);
|
||||
}
|
||||
|
||||
var addMetadataRect = rect.AlignTop(addButtonAreaHeight).AlignCenter(Mathf.Min(200, rect.width - 16)).VerticalPadding(8);
|
||||
|
||||
if (GUI.Button(addMetadataRect, "Add Metadata"))
|
||||
{
|
||||
openMetadataSelector();
|
||||
}
|
||||
|
||||
// Draw the shadow that appears under the search bar while scrolling through the metadata.
|
||||
GUI.DrawTexture(
|
||||
searchAreaRect.AlignBottom(10).AddY(10),
|
||||
OdinLocalizationGUITextures.TopToBottomFade,
|
||||
ScaleMode.StretchToFill,
|
||||
true,
|
||||
1.0f,
|
||||
new Color(0, 0, 0, Mathf.InverseLerp(0f, 30f, this.scrollPosition.y) * 0.6f),
|
||||
0,
|
||||
0);
|
||||
|
||||
if (measureRect.height > metadataViewHeight)
|
||||
{
|
||||
var pos = this.scrollPosition.y + metadataViewHeight;
|
||||
// Draw the shadow that appears at the bottom of the metadata while scrolling through the metadata
|
||||
GUI.DrawTexture(
|
||||
rect.AlignTop(10).SubY(10),
|
||||
OdinLocalizationGUITextures.BottomToTopFade,
|
||||
ScaleMode.StretchToFill,
|
||||
true,
|
||||
1.0f,
|
||||
new Color(0, 0, 0, Mathf.InverseLerp(measureRect.height, measureRect.height - 30, pos) * 0.6f),
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
return measureRect.width;
|
||||
}
|
||||
|
||||
private void DrawPlatformOverride(InspectorProperty metadataEntry)
|
||||
{
|
||||
var platformOverride = (PlatformOverride)metadataEntry.ValueEntry.WeakSmartValue;
|
||||
var platformOverrideDatas = (IList)metadataEntry.Children["m_PlatformOverrides"]?.ValueEntry.WeakSmartValue;
|
||||
var platformOverrideDataInspectorProperties = metadataEntry.Children["m_PlatformOverrides"]?.Children;
|
||||
|
||||
if (platformOverrideDatas == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (platformOverrideDatas.Count == 0)
|
||||
{
|
||||
platformOverride.AddPlatformOverride(RuntimePlatform.WindowsPlayer, null, null, EntryOverrideType.None);
|
||||
}
|
||||
|
||||
for (var i = 0; i < platformOverrideDataInspectorProperties.Count; i++)
|
||||
{
|
||||
var platformOverrideDataInspectorProperty = platformOverrideDataInspectorProperties[i];
|
||||
var backgroundRect = EditorGUILayout.BeginVertical(this.PlatformOverridePadding);
|
||||
var backgroundColor = i % 2 == 0 ? SirenixGUIStyles.ListItemColorEven : SirenixGUIStyles.ListItemColorOdd;
|
||||
EditorGUI.DrawRect(backgroundRect, backgroundColor);
|
||||
platformOverrideDataInspectorProperty.Children["platform"].Draw();
|
||||
platformOverrideDataInspectorProperty.Children["entryOverrideType"].Draw();
|
||||
|
||||
var entryOverrideType = (EntryOverrideType)platformOverrideDataInspectorProperty.Children
|
||||
.FirstOrDefault(c => c.Info.TypeOfValue == typeof(EntryOverrideType))?.ValueEntry.WeakSmartValue;
|
||||
|
||||
var entryOverrideRect = GUILayoutUtility.GetRect(0, EditorGUIUtility.singleLineHeight, GUILayoutOptions.ExpandWidth(true).ExpandHeight(false));
|
||||
|
||||
switch (entryOverrideType)
|
||||
{
|
||||
case EntryOverrideType.Table:
|
||||
{
|
||||
var tableReference = (TableReference)platformOverrideDataInspectorProperty.Children.FirstOrDefault(c => c.Info.TypeOfValue == typeof(TableReference))?.ValueEntry.WeakSmartValue;
|
||||
this.DoTableGUI(entryOverrideRect, tableReference, platformOverrideDataInspectorProperty);
|
||||
break;
|
||||
}
|
||||
case EntryOverrideType.Entry:
|
||||
{
|
||||
var tableReference = (TableReference)platformOverrideDataInspectorProperty.Children.FirstOrDefault(c => c.Info.TypeOfValue == typeof(TableReference))
|
||||
?.ValueEntry.WeakSmartValue;
|
||||
var tableEntryReference = (TableEntryReference)platformOverrideDataInspectorProperty.Children.FirstOrDefault(c => c.Info.TypeOfValue == typeof(TableEntryReference))?.ValueEntry.WeakSmartValue;
|
||||
this.DoTableAndEntryGUI(entryOverrideRect, tableReference, tableEntryReference, platformOverrideDataInspectorProperty, false);
|
||||
break;
|
||||
}
|
||||
|
||||
case EntryOverrideType.TableAndEntry:
|
||||
{
|
||||
var tableReference = (TableReference)platformOverrideDataInspectorProperty.Children.FirstOrDefault(c => c.Info.TypeOfValue == typeof(TableReference))?.ValueEntry.WeakSmartValue;
|
||||
var tableEntryReference = (TableEntryReference)platformOverrideDataInspectorProperty.Children.FirstOrDefault(c => c.Info.TypeOfValue == typeof(TableEntryReference))?.ValueEntry.WeakSmartValue;
|
||||
this.DoTableAndEntryGUI(entryOverrideRect, tableReference, tableEntryReference, platformOverrideDataInspectorProperty, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
var xIconRect = backgroundRect.AlignRight(10).SubX(4).AlignCenterY(10);
|
||||
var mouseOverX = Event.current.IsMouseOver(xIconRect);
|
||||
SdfIcons.DrawIcon(xIconRect, SdfIconType.X, mouseOverX ? Color.white : EditorStyles.label.normal.textColor);
|
||||
|
||||
if (Event.current.OnMouseDown(xIconRect, 0, false))
|
||||
{
|
||||
var platform = (RuntimePlatform)platformOverrideDataInspectorProperty.Children[0].ValueEntry.WeakSmartValue;
|
||||
platformOverride.RemovePlatformOverride(platform);
|
||||
}
|
||||
}
|
||||
|
||||
var addButtonRect = GUILayoutUtility.GetRect(0, 40, GUILayoutOptions.ExpandWidth().ExpandHeight(false));
|
||||
EditorGUI.DrawRect(addButtonRect.AlignTop(1), new Color(0.188f, 0.188f, 0.188f));
|
||||
|
||||
if (GUI.Button(addButtonRect.Padding(8), "Add Platform Override"))
|
||||
{
|
||||
var selector = new EnumSelector<RuntimePlatform>();
|
||||
selector.SelectionConfirmed += platforms =>
|
||||
{
|
||||
var platform = platforms.FirstOrDefault();
|
||||
platformOverride.AddPlatformOverride(platform, null, null, EntryOverrideType.None);
|
||||
};
|
||||
selector.ShowInPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenMetadataSelector(LocalizationTableCollection localizationTableCollection)
|
||||
{
|
||||
this.OpenMetadataSelector(localizationTableCollection.SharedData.Metadata.MetadataEntries, MetadataType.SharedTableData);
|
||||
}
|
||||
|
||||
private void OpenMetadataSelector(LocalizationTable localizationTable)
|
||||
{
|
||||
switch (localizationTable)
|
||||
{
|
||||
case StringTable _:
|
||||
this.OpenMetadataSelector(localizationTable.MetadataEntries, MetadataType.StringTable);
|
||||
break;
|
||||
case AssetTable _:
|
||||
this.OpenMetadataSelector(localizationTable.MetadataEntries, MetadataType.AssetTable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenMetadataSelector(SharedTableData.SharedTableEntry sharedTableEntry)
|
||||
{
|
||||
switch (this.localizationTableCollection)
|
||||
{
|
||||
case StringTableCollection _:
|
||||
this.OpenMetadataSelector(sharedTableEntry.Metadata.MetadataEntries, MetadataType.StringTableEntry, MetadataType.SharedStringTableEntry);
|
||||
break;
|
||||
case AssetTableCollection _:
|
||||
this.OpenMetadataSelector(sharedTableEntry.Metadata.MetadataEntries, MetadataType.AssetTableEntry, MetadataType.SharedAssetTableEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenMetadataSelector(TableEntry tableEntry)
|
||||
{
|
||||
switch (tableEntry)
|
||||
{
|
||||
case StringTableEntry _:
|
||||
this.OpenMetadataSelector(tableEntry.MetadataEntries, MetadataType.StringTableEntry);
|
||||
break;
|
||||
case AssetTableEntry _:
|
||||
this.OpenMetadataSelector(tableEntry.MetadataEntries, MetadataType.AssetTableEntry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenMetadataSelector(IList<IMetadata> existingMetadata, params MetadataType[] allowedTypes)
|
||||
{
|
||||
var existingMetadataTypes = existingMetadata.Select(m => m?.GetType()).ToList();
|
||||
var metadataTypes = TypeCache.GetTypesDerivedFrom<IMetadata>();
|
||||
var validMetadataTypes = new List<Type>();
|
||||
|
||||
foreach (var metadataType in metadataTypes)
|
||||
{
|
||||
var metadataAttribute = metadataType.GetCustomAttribute<MetadataAttribute>();
|
||||
if (metadataAttribute != null && allowedTypes.Any(allowedType => metadataAttribute.AllowedTypes.HasFlag(allowedType)))
|
||||
{
|
||||
if (existingMetadataTypes.Contains(metadataType) && !OdinLocalizationMetadataRegistry.MetadataAllowsMultiple.ContainsKey(metadataType)) continue;
|
||||
|
||||
validMetadataTypes.Add(metadataType);
|
||||
}
|
||||
}
|
||||
|
||||
var selector = new GenericSelector<Type>("", validMetadataTypes, false, type => ObjectNames.NicifyVariableName(type.Name));
|
||||
|
||||
foreach (var item in selector.SelectionTree.MenuItems)
|
||||
{
|
||||
item.SdfIcon = SdfIconType.Braces;
|
||||
}
|
||||
|
||||
selector.SelectionConfirmed += types =>
|
||||
{
|
||||
var selectedType = types.FirstOrDefault();
|
||||
|
||||
if (selectedType == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var metadata = (IMetadata)Activator.CreateInstance(selectedType);
|
||||
this.toBeAdded = metadata;
|
||||
};
|
||||
selector.EnableSingleClickToSelect();
|
||||
selector.ShowInPopup();
|
||||
}
|
||||
|
||||
public class TableReferenceSelector : OdinSelector<LocalizationTableCollection>
|
||||
{
|
||||
private Type tableType;
|
||||
|
||||
public TableReferenceSelector(Type tableType)
|
||||
{
|
||||
this.tableType = tableType;
|
||||
}
|
||||
|
||||
protected override void BuildSelectionTree(OdinMenuTree tree)
|
||||
{
|
||||
tree.Config.SelectMenuItemsOnMouseDown = true;
|
||||
tree.Selection.SupportsMultiSelect = false;
|
||||
|
||||
var collectionGUIDs = AssetDatabase.FindAssets($"t:{nameof(LocalizationTableCollection)}");
|
||||
|
||||
foreach (var guid in collectionGUIDs)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var collection = AssetDatabase.LoadAssetAtPath<LocalizationTableCollection>(path);
|
||||
|
||||
if (collection is null) continue;
|
||||
if (collection.Tables.Count < 1) continue;
|
||||
if (collection.Tables[0].asset.GetType() != this.tableType) continue;
|
||||
|
||||
var collectionItem = new OdinMenuItem(tree, collection.name, collection)
|
||||
{
|
||||
SdfIcon = SdfIconType.Table
|
||||
};
|
||||
|
||||
tree.MenuItems.Add(collectionItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TableEntryReferenceSelector : OdinSelector<TableEntryReferenceSelector.TableEntry>
|
||||
{
|
||||
private Type tableType;
|
||||
|
||||
public struct TableEntry
|
||||
{
|
||||
public LocalizationTableCollection Collection;
|
||||
public SharedTableData.SharedTableEntry SharedEntry;
|
||||
}
|
||||
|
||||
public TableEntryReferenceSelector(Type tableType)
|
||||
{
|
||||
this.tableType = tableType;
|
||||
}
|
||||
|
||||
protected override void BuildSelectionTree(OdinMenuTree tree)
|
||||
{
|
||||
tree.Config.SelectMenuItemsOnMouseDown = true;
|
||||
tree.Selection.SupportsMultiSelect = false;
|
||||
|
||||
|
||||
var collectionGUIDs = AssetDatabase.FindAssets($"t:{nameof(LocalizationTableCollection)}");
|
||||
|
||||
foreach (var guid in collectionGUIDs)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var collection = AssetDatabase.LoadAssetAtPath<LocalizationTableCollection>(path);
|
||||
|
||||
if (collection is null) continue;
|
||||
if (collection.Tables.Count < 1) continue;
|
||||
if (collection.Tables[0].asset.GetType() != this.tableType) continue;
|
||||
|
||||
var collectionItem = new OdinMenuItem(tree, collection.name, collection)
|
||||
{
|
||||
SdfIcon = SdfIconType.Table
|
||||
};
|
||||
|
||||
List<SharedTableData.SharedTableEntry> entries = collection.SharedData.Entries;
|
||||
|
||||
for (var j = 0; j < entries.Count; j++)
|
||||
{
|
||||
SharedTableData.SharedTableEntry entry = entries[j];
|
||||
|
||||
var tableEntry = new TableEntry {Collection = collection, SharedEntry = entry};
|
||||
|
||||
var entryItem = new OdinMenuItem(tree, entry.Key, tableEntry)
|
||||
{
|
||||
SdfIcon = SdfIconType.KeyFill
|
||||
};
|
||||
|
||||
collectionItem.ChildMenuItems.Add(entryItem);
|
||||
}
|
||||
|
||||
collectionItem.IsSelectable = false;
|
||||
tree.MenuItems.Add(collectionItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoTableGUI(Rect rect, TableReference tableReference, InspectorProperty platformOverrideData)
|
||||
{
|
||||
var dropDownPosition = EditorGUI.PrefixLabel(rect, new GUIContent("Table Collection"));
|
||||
var label = tableReference.TableCollectionName;
|
||||
|
||||
if (EditorGUI.DropdownButton(dropDownPosition, new GUIContent(label), FocusType.Passive))
|
||||
{
|
||||
TableReferenceSelector tableReferenceSelector;
|
||||
|
||||
tableReferenceSelector = this.localizationTableCollection.GetType() == typeof(AssetTableCollection)
|
||||
? new TableReferenceSelector(typeof(AssetTable))
|
||||
: new TableReferenceSelector(typeof(StringTable));
|
||||
|
||||
tableReferenceSelector.GetCurrentSelection();
|
||||
|
||||
tableReferenceSelector.SelectionConfirmed += selections =>
|
||||
{
|
||||
var selection = selections.FirstOrDefault();
|
||||
|
||||
var platformOverrideType = typeof(PlatformOverride);
|
||||
var platformOverrideDataType = platformOverrideType.GetNestedType("PlatformOverrideData", BindingFlags.NonPublic);
|
||||
|
||||
platformOverrideDataType
|
||||
.GetField("tableReference")
|
||||
.SetValue(platformOverrideData.ValueEntry.WeakSmartValue, selection.TableCollectionNameReference);
|
||||
|
||||
platformOverrideDataType
|
||||
.GetField("tableEntryReference")
|
||||
.SetValue(platformOverrideData.ValueEntry.WeakSmartValue, (TableEntryReference) string.Empty);
|
||||
};
|
||||
|
||||
tableReferenceSelector.ShowInPopup();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoTableAndEntryGUI(Rect rect,
|
||||
TableReference tableReference,
|
||||
TableEntryReference tableEntryReference,
|
||||
InspectorProperty platformOverrideData,
|
||||
bool displayTableName)
|
||||
{
|
||||
var dropDownPosition = EditorGUI.PrefixLabel(rect, new GUIContent("Reference"));
|
||||
|
||||
var entryLabel = tableEntryReference.ReferenceType != TableEntryReference.Type.Empty
|
||||
? tableEntryReference.ResolveKeyName(this.localizationTableCollection.SharedData)
|
||||
: null;
|
||||
|
||||
string label;
|
||||
if (displayTableName)
|
||||
{
|
||||
var tableLabel = tableReference.TableCollectionName ?? "";
|
||||
label = string.IsNullOrEmpty(tableLabel) || string.IsNullOrEmpty(entryLabel) ? "None" : $"{tableLabel}/{entryLabel}";
|
||||
}
|
||||
else
|
||||
{
|
||||
label = string.IsNullOrWhiteSpace(entryLabel) ? "None" : $"{entryLabel}";
|
||||
}
|
||||
|
||||
if (EditorGUI.DropdownButton(dropDownPosition, new GUIContent(label), FocusType.Passive))
|
||||
{
|
||||
Type tableType = this.localizationTableCollection.GetType() == typeof(AssetTableCollection)
|
||||
? typeof(AssetTable)
|
||||
: typeof(StringTable);
|
||||
|
||||
TableEntryReferenceSelector tableEntryReferenceSelector = new TableEntryReferenceSelector(tableType);
|
||||
tableEntryReferenceSelector.SelectionConfirmed += selections =>
|
||||
{
|
||||
var selection = selections.FirstOrDefault();
|
||||
var platformOverrideType = typeof(PlatformOverride);
|
||||
var platformOverrideDataType = platformOverrideType.GetNestedType("PlatformOverrideData", BindingFlags.NonPublic);
|
||||
|
||||
platformOverrideDataType
|
||||
.GetField("tableReference")
|
||||
.SetValue(platformOverrideData.ValueEntry.WeakSmartValue, selection.Collection.TableCollectionNameReference);
|
||||
|
||||
platformOverrideDataType
|
||||
.GetField("tableEntryReference")
|
||||
.SetValue(platformOverrideData.ValueEntry.WeakSmartValue, (TableEntryReference) selection.SharedEntry.Key);
|
||||
};
|
||||
|
||||
tableEntryReferenceSelector.ShowInPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1490cea564e237341b75e0cdba1f374a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc0d9dcd4d4f4e3094085c752e185ef8
|
||||
timeCreated: 1704811181
|
||||
@@ -0,0 +1,196 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinGUITable.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define USING_WIDTH_NON_PERCENT
|
||||
//#undef USING_WIDTH_NON_PERCENT
|
||||
|
||||
using System;
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class OdinGUITable<TTable> : IComparable<OdinGUITable<TTable>> where TTable : LocalizationTable
|
||||
{
|
||||
public const string KEY_DISPLAY_NAME = "Key";
|
||||
|
||||
public enum GUITableType
|
||||
{
|
||||
Default,
|
||||
Key
|
||||
}
|
||||
|
||||
public float Width
|
||||
{
|
||||
get => this._width;
|
||||
set
|
||||
{
|
||||
if (value < OdinLocalizationConstants.MIN_COLUMN_WIDTH)
|
||||
{
|
||||
this._width = OdinLocalizationConstants.MIN_COLUMN_WIDTH;
|
||||
return;
|
||||
}
|
||||
|
||||
this._width = Mathf.Round(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDraggingSlider = false;
|
||||
public bool IsVisible;
|
||||
public string DisplayName;
|
||||
public GUITableType Type;
|
||||
|
||||
[FormerlySerializedAs("Table")]
|
||||
public TTable Asset;
|
||||
public bool IsPinned;
|
||||
|
||||
private float _width;
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
//public float VisualWidth;
|
||||
#else
|
||||
internal float WidthPercentage;
|
||||
#endif
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
public static OdinGUITable<TTable> CreateKeyTable()
|
||||
#else
|
||||
public static OdinGUITable<TTable> CreateKeyTable(float widthPercent)
|
||||
#endif
|
||||
{
|
||||
return new OdinGUITable<TTable>
|
||||
{
|
||||
IsVisible = true,
|
||||
DisplayName = KEY_DISPLAY_NAME,
|
||||
Type = GUITableType.Key,
|
||||
Asset = null,
|
||||
IsPinned = false,
|
||||
Width = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH,
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
// VisualWidth = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH
|
||||
#else
|
||||
WidthPercentage = widthPercent
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
public static OdinGUITable<TTable> CreateTable(TTable table, Locale locale)
|
||||
#else
|
||||
public static OdinGUITable<TTable> CreateTable(TTable table, float widthPercent)
|
||||
#endif
|
||||
{
|
||||
return new OdinGUITable<TTable>
|
||||
{
|
||||
IsVisible = true,
|
||||
DisplayName = locale.LocaleName,
|
||||
Type = GUITableType.Default,
|
||||
Asset = table,
|
||||
IsPinned = false,
|
||||
Width = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH,
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
// VisualWidth = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH
|
||||
#else
|
||||
WidthPercentage = widthPercent
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
public int CompareTo(OdinGUITable<TTable> other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this.IsVisible && !other.IsVisible)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!this.IsVisible && other.IsVisible)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.IsPinned && !other.IsPinned)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!this.IsPinned && other.IsPinned)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.DisplayName == KEY_DISPLAY_NAME && other.DisplayName == KEY_DISPLAY_NAME)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (other.DisplayName == KEY_DISPLAY_NAME)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this.DisplayName == KEY_DISPLAY_NAME)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return this.Asset.LocaleIdentifier.CompareTo(other.Asset.LocaleIdentifier);
|
||||
}
|
||||
|
||||
public Vector2 HandleSlider(Rect position)
|
||||
{
|
||||
if (GUIUtility.hotControl == 0)
|
||||
{
|
||||
this.IsDraggingSlider = false;
|
||||
}
|
||||
|
||||
if (!GUI.enabled)
|
||||
{
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
EditorGUIUtility.AddCursorRect(position, MouseCursor.ResizeHorizontal);
|
||||
|
||||
if (GUI.enabled && Event.current.OnMouseDown(position, 0))
|
||||
{
|
||||
this.IsDraggingSlider = true;
|
||||
SharedUniqueControlId.SetActive();
|
||||
EditorGUIUtility.SetWantsMouseJumping(1);
|
||||
Event.current.Use();
|
||||
}
|
||||
else if (SharedUniqueControlId.IsActive && this.IsDraggingSlider)
|
||||
{
|
||||
if (Event.current.type == EventType.MouseDrag)
|
||||
{
|
||||
Event.current.Use();
|
||||
GUI.changed = true;
|
||||
return Event.current.delta;
|
||||
}
|
||||
|
||||
if (Event.current.type != EventType.MouseUp)
|
||||
{
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
this.IsDraggingSlider = false;
|
||||
SharedUniqueControlId.SetInactive();
|
||||
EditorGUIUtility.SetWantsMouseJumping(0);
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
return Vector2.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6172b1a79444464bfac84d14344febf
|
||||
timeCreated: 1706411334
|
||||
@@ -0,0 +1,483 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinGUITableCollection.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define USING_WIDTH_NON_PERCENT
|
||||
//#undef USING_WIDTH_NON_PERCENT
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class OdinGUITableCollection<TTable> : List<OdinGUITable<TTable>> where TTable : LocalizationTable
|
||||
{
|
||||
public readonly struct VisibleTables
|
||||
{
|
||||
public readonly int Offset;
|
||||
public readonly int Length;
|
||||
public readonly int PinnedLength;
|
||||
public readonly float StartOffset;
|
||||
|
||||
private readonly OdinGUITableCollection<TTable> collection;
|
||||
|
||||
public VisibleTables(OdinGUITableCollection<TTable> collection, int offset, int length, int pinnedLength, float startOffset)
|
||||
{
|
||||
this.collection = collection;
|
||||
this.Offset = offset;
|
||||
this.Length = length + pinnedLength;
|
||||
this.PinnedLength = pinnedLength;
|
||||
this.StartOffset = startOffset;
|
||||
}
|
||||
|
||||
public OdinGUITable<TTable> this[int index] =>
|
||||
index >= this.PinnedLength ? this.collection[this.Offset + index - this.PinnedLength] : this.collection[index];
|
||||
}
|
||||
|
||||
//public VisibleTables CurrentVisibleTables;
|
||||
|
||||
public HashSet<OdinGUITable<TTable>> TablesWithinVisibleBounds = new HashSet<OdinGUITable<TTable>>();
|
||||
|
||||
public OdinGUITableCollection(int capacity) : base(capacity) { }
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
public void AddKeyTable()
|
||||
{
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].Type == OdinGUITable<TTable>.GUITableType.Key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.Add(OdinGUITable<TTable>.CreateKeyTable());
|
||||
}
|
||||
#else
|
||||
public void AddKeyTable(float widthPercent)
|
||||
{
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].Type == OdinGUITable<TTable>.GUITableType.Key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.Add(OdinGUITable<TTable>.CreateKeyTable(widthPercent));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
public void UpdateVisibleTables(OdinGUIScrollView view, float pinnedWidth)
|
||||
{
|
||||
#if true
|
||||
this.TablesWithinVisibleBounds.Clear();
|
||||
|
||||
var offset = 0;
|
||||
var currentVisibleWidth = 0.0f;
|
||||
var xMin = 0.0f;
|
||||
var xMax = 0.0f;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
OdinGUITable<TTable> table = this[i];
|
||||
|
||||
if (!table.IsVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table.IsPinned)
|
||||
{
|
||||
this.TablesWithinVisibleBounds.Add(table);
|
||||
continue;
|
||||
}
|
||||
|
||||
xMax += table.Width;
|
||||
|
||||
bool isVisible = view.Position.x >= xMin && view.Position.x <= xMax;
|
||||
|
||||
if (!isVisible)
|
||||
{
|
||||
xMin = xMax;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = i;
|
||||
|
||||
currentVisibleWidth = xMax - view.Position.x;
|
||||
this.TablesWithinVisibleBounds.Add(table);
|
||||
break;
|
||||
}
|
||||
|
||||
float width = view.Bounds.width - pinnedWidth;
|
||||
|
||||
for (int i = offset + 1; i < this.Count; i++)
|
||||
{
|
||||
OdinGUITable<TTable> table = this[i];
|
||||
|
||||
if (!table.IsVisible)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentVisibleWidth >= width)
|
||||
{
|
||||
this.TablesWithinVisibleBounds.Add(table);
|
||||
break;
|
||||
}
|
||||
|
||||
this.TablesWithinVisibleBounds.Add(table);
|
||||
currentVisibleWidth += this[i].Width;
|
||||
}
|
||||
#else
|
||||
if (this.GetVisibleCount() < 1)
|
||||
{
|
||||
this.CurrentVisibleTables = new VisibleTables(this, 0, 0, 0, 0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
const int LENGTH_NOT_SET = -1;
|
||||
|
||||
var offset = 0;
|
||||
int length = LENGTH_NOT_SET;
|
||||
|
||||
var currentVisibleWidth = 0.0f;
|
||||
|
||||
float xMin = 0.0f, xMax = 0.0f;
|
||||
|
||||
float positionX = view.Position.x;
|
||||
float width = view.Bounds.width - pinnedWidth;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
OdinGUITable<TTable> table = this[i];
|
||||
|
||||
if (table.IsPinned)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!table.IsVisible)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
xMax += table.VisualWidth;
|
||||
|
||||
bool isVisible = positionX >= xMin && positionX <= xMax;
|
||||
|
||||
if (!isVisible)
|
||||
{
|
||||
xMin = xMax;
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = i;
|
||||
|
||||
currentVisibleWidth = xMax - positionX;
|
||||
break;
|
||||
}
|
||||
|
||||
float startOffset = xMin;
|
||||
|
||||
for (int i = offset + 1; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsVisible)
|
||||
{
|
||||
length = i - offset;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentVisibleWidth >= width)
|
||||
{
|
||||
length = i - offset + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
currentVisibleWidth += this[i].VisualWidth;
|
||||
}
|
||||
|
||||
int pinnedCount = this.GetPinnedCount();
|
||||
|
||||
if (length == LENGTH_NOT_SET)
|
||||
{
|
||||
length = this.Count - offset;
|
||||
}
|
||||
|
||||
this.CurrentVisibleTables = new VisibleTables(this, offset, length, pinnedCount, startOffset);
|
||||
#endif
|
||||
}
|
||||
|
||||
public float GetVisibleWidth()
|
||||
{
|
||||
var result = 0.0f;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsVisible)
|
||||
{
|
||||
result += this[i].Width;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void ResizeBy(float factor)
|
||||
{
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsVisible)
|
||||
{
|
||||
this[i].Width *= factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// <summary> Calculates the <see cref="GUITable.Width"/> field on <see cref="GUITable"/> beforehand. </summary>
|
||||
/// <param name="scrollView">The <see cref="OdinGUIScrollView"/> to perform calculations on.</param>
|
||||
public void CalcWidths(OdinGUIScrollView scrollView)
|
||||
{
|
||||
float viewWidth = scrollView.ViewRect.width;
|
||||
|
||||
float visibleFactor = this.GetVisibleFactor();
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
this[i].Width = viewWidth * (this[i].WidthPercentage * visibleFactor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public int GetLastVisibleIndex()
|
||||
{
|
||||
for (int i = this.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (this[i].IsVisible)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetLastVisiblePinnedIndex()
|
||||
{
|
||||
for (int i = this.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (this[i].IsVisible && this[i].IsPinned)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetVisibleCount()
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsVisible)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetHiddenCount()
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsVisible)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int GetPinnedCount()
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsVisible && this[i].IsPinned)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public OdinGUITable<TTable> GetNextVisible(int index)
|
||||
{
|
||||
for (int i = index + 1; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsVisible)
|
||||
{
|
||||
return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void UndoRecordCollection(SharedTableData sharedTableData, string name)
|
||||
{
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
switch (this[i].Type)
|
||||
{
|
||||
case OdinGUITable<TTable>.GUITableType.Default:
|
||||
Undo.RecordObject(this[i].Asset, name);
|
||||
break;
|
||||
|
||||
case OdinGUITable<TTable>.GUITableType.Key:
|
||||
if (sharedTableData != null)
|
||||
{
|
||||
Undo.RecordObject(sharedTableData, name);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDirty(SharedTableData sharedTableData)
|
||||
{
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
switch (this[i].Type)
|
||||
{
|
||||
case OdinGUITable<TTable>.GUITableType.Default:
|
||||
EditorUtility.SetDirty(this[i].Asset);
|
||||
break;
|
||||
|
||||
case OdinGUITable<TTable>.GUITableType.Key:
|
||||
if (sharedTableData != null)
|
||||
{
|
||||
EditorUtility.SetDirty(sharedTableData);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !USING_WIDTH_NON_PERCENT
|
||||
private float GetVisibleFactor()
|
||||
{
|
||||
var visibleCount = 0;
|
||||
var sum = 0.0f;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sum += this[i].WidthPercentage;
|
||||
visibleCount++;
|
||||
}
|
||||
|
||||
float result = (float) this.Count / visibleCount;
|
||||
|
||||
sum *= result;
|
||||
|
||||
result *= 1.0f / sum;
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
public void ResizeToFit(float targetWidth)
|
||||
{
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (this[i].IsPinned || !this[i].IsVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int averageSize = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH * count;
|
||||
|
||||
float scaleFactor = targetWidth / averageSize;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsVisible || this[i].IsPinned)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this[i].Width = OdinLocalizationConstants.DEFAULT_COLUMN_WIDTH * scaleFactor;
|
||||
}
|
||||
}
|
||||
|
||||
public void ResizePinnedToFit(float targetWidth)
|
||||
{
|
||||
var currentTotalWidth = 0.0f;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsPinned || !this[i].IsVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
currentTotalWidth += this[i].Width;
|
||||
}
|
||||
|
||||
if (currentTotalWidth < 1.0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float scaleFactor = targetWidth / currentTotalWidth;
|
||||
|
||||
for (var i = 0; i < this.Count; i++)
|
||||
{
|
||||
if (!this[i].IsVisible || !this[i].IsPinned)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this[i].Width *= scaleFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a739bb40d31496a9591094d81fd2d19
|
||||
timeCreated: 1706411492
|
||||
@@ -0,0 +1,441 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinSharedEntryCollection.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class OdinSharedEntryCollection
|
||||
{
|
||||
private class StringComparer : IComparer<string>
|
||||
{
|
||||
public bool IsAscending = true;
|
||||
|
||||
public int Compare(string self, string other)
|
||||
{
|
||||
if (string.IsNullOrEmpty(self) && string.IsNullOrEmpty(other))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(self))
|
||||
{
|
||||
return this.IsAscending ? 1 : -1;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(other))
|
||||
{
|
||||
return this.IsAscending ? -1 : 1;
|
||||
}
|
||||
|
||||
return string.Compare(self, other, StringComparison.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SortOrderState
|
||||
{
|
||||
Unsorted,
|
||||
Ascending,
|
||||
Descending
|
||||
}
|
||||
|
||||
public bool IsSearching;
|
||||
|
||||
public bool IsSorted => this.CurrentSortOrderState != SortOrderState.Unsorted;
|
||||
|
||||
public int Length => this.Entries.Count;
|
||||
|
||||
private string _searchTerm = string.Empty;
|
||||
|
||||
private StringComparer stringComparer = new StringComparer();
|
||||
|
||||
public string SearchTerm
|
||||
{
|
||||
get => this._searchTerm;
|
||||
private set
|
||||
{
|
||||
this._searchTerm = value;
|
||||
|
||||
this.IsSearching = !string.IsNullOrEmpty(value);
|
||||
}
|
||||
}
|
||||
|
||||
public List<SharedTableData.SharedTableEntry> Entries => this.IsSorted ? this.SortedEntries : this.Collection.SharedData.Entries;
|
||||
|
||||
public List<SharedTableData.SharedTableEntry> SortedEntries;
|
||||
public readonly HashSet<SharedTableData.SharedTableEntry> FilteredEntries;
|
||||
|
||||
public readonly LocalizationTableCollection Collection;
|
||||
|
||||
public SortOrderState CurrentSortOrderState = SortOrderState.Unsorted;
|
||||
|
||||
public OdinSharedEntryCollection(LocalizationTableCollection collection)
|
||||
{
|
||||
this.Collection = collection;
|
||||
|
||||
this.FilteredEntries = new HashSet<SharedTableData.SharedTableEntry>();
|
||||
}
|
||||
|
||||
public SharedTableData.SharedTableEntry this[int index] => this.Entries[index];
|
||||
|
||||
public bool IsVisible(SharedTableData.SharedTableEntry sharedEntry)
|
||||
{
|
||||
return !this.IsSearching || (this.IsSearching && this.FilteredEntries.Contains(sharedEntry));
|
||||
}
|
||||
|
||||
public bool UpdateSearchTerm<TTable>(string value,
|
||||
OdinGUITableCollection<TTable> tables,
|
||||
LocalizationTableCollection collection,
|
||||
bool forceUpdate = false) where TTable : LocalizationTable
|
||||
{
|
||||
if (this.SearchTerm == value && !forceUpdate)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.SearchTerm = value;
|
||||
|
||||
if (string.IsNullOrEmpty(this.SearchTerm))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
this.FilteredEntries.Clear();
|
||||
|
||||
for (var i = 0; i < tables.Count; i++)
|
||||
{
|
||||
OdinGUITable<TTable> table = tables[i];
|
||||
|
||||
switch (table.Type)
|
||||
{
|
||||
case OdinGUITable<TTable>.GUITableType.Default:
|
||||
switch (table.Asset)
|
||||
{
|
||||
case AssetTable assetTable:
|
||||
var assetCollection = collection as AssetTableCollection;
|
||||
|
||||
for (var j = 0; j < this.Length; j++)
|
||||
{
|
||||
SharedTableData.SharedTableEntry sharedEntry = this[j];
|
||||
|
||||
Type assetType = assetCollection.GetEntryAssetType(sharedEntry.Id);
|
||||
|
||||
UnityEngine.Object asset = OdinLocalizationAssetCache.Get(sharedEntry, assetTable, assetType);
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FuzzySearch.Contains(this.SearchTerm, asset.name))
|
||||
{
|
||||
this.FilteredEntries.Add(sharedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case StringTable stringTable:
|
||||
for (var j = 0; j < this.Length; j++)
|
||||
{
|
||||
SharedTableData.SharedTableEntry sharedEntry = this[j];
|
||||
|
||||
StringTableEntry entry = stringTable.GetEntry(sharedEntry.Id);
|
||||
|
||||
if (entry is null || string.IsNullOrEmpty(entry.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FuzzySearch.Contains(this.SearchTerm, entry.Value))
|
||||
{
|
||||
this.FilteredEntries.Add(sharedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OdinGUITable<TTable>.GUITableType.Key:
|
||||
for (var j = 0; j < this.Entries.Count; j++)
|
||||
{
|
||||
if (FuzzySearch.Contains(this.SearchTerm, this.Entries[j].Key))
|
||||
{
|
||||
this.FilteredEntries.Add(this.Entries[j]);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SortByKeys(bool preserveCurrentOrder)
|
||||
{
|
||||
switch (this.CurrentSortOrderState)
|
||||
{
|
||||
case SortOrderState.Ascending:
|
||||
this.stringComparer.IsAscending = true;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries.OrderBy(entry => entry.Key, this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Collection.SharedData.Entries.OrderBy(entry => entry.Key, this.stringComparer).ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case SortOrderState.Descending:
|
||||
this.stringComparer.IsAscending = false;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries.OrderByDescending(entry => entry.Key, this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Collection.SharedData.Entries.OrderByDescending(entry => entry.Key, this.stringComparer).ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void SortByAssetTable(AssetTableCollection collection, AssetTable table, bool preserveCurrentOrder)
|
||||
{
|
||||
switch (this.CurrentSortOrderState)
|
||||
{
|
||||
case SortOrderState.Ascending:
|
||||
this.stringComparer.IsAscending = true;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries
|
||||
.OrderBy(entry => GetAssetNameFromEntry(entry, table, collection), this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Collection.SharedData.Entries.OrderBy(entry => GetAssetNameFromEntry(entry, table, collection), this.stringComparer)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case SortOrderState.Descending:
|
||||
this.stringComparer.IsAscending = false;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries
|
||||
.OrderByDescending(entry => GetAssetNameFromEntry(entry, table, collection),
|
||||
this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Entries.OrderByDescending(entry => GetAssetNameFromEntry(entry, table, collection), this.stringComparer).ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void SortByStringTable(StringTable table, bool preserveCurrentOrder)
|
||||
{
|
||||
switch (this.CurrentSortOrderState)
|
||||
{
|
||||
case SortOrderState.Ascending:
|
||||
this.stringComparer.IsAscending = true;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries
|
||||
.OrderBy(entry => GetStringFromEntry(entry, table), this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Collection.SharedData.Entries.OrderBy(entry => GetStringFromEntry(entry, table), this.stringComparer).ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
case SortOrderState.Descending:
|
||||
this.stringComparer.IsAscending = false;
|
||||
|
||||
if (preserveCurrentOrder)
|
||||
{
|
||||
List<SharedTableData.SharedTableEntry> result = this.Collection.SharedData.Entries
|
||||
.OrderByDescending(entry => GetStringFromEntry(entry, table), this.stringComparer)
|
||||
.ThenBy(this.GetOrderIndex)
|
||||
.ToList();
|
||||
|
||||
this.SortedEntries = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SortedEntries = this.Entries.OrderByDescending(entry => GetStringFromEntry(entry, table), this.stringComparer).ToList();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetStringFromEntry(SharedTableData.SharedTableEntry sharedEntry, StringTable table)
|
||||
{
|
||||
StringTableEntry entry = table.GetEntry(sharedEntry.Id);
|
||||
|
||||
return entry?.Value;
|
||||
}
|
||||
|
||||
private static string GetAssetNameFromEntry(SharedTableData.SharedTableEntry sharedEntry, AssetTable table, AssetTableCollection collection)
|
||||
{
|
||||
AssetTableEntry entry = table.GetEntry(sharedEntry.Id);
|
||||
|
||||
if (entry == null || entry.IsEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Type type = collection.GetEntryAssetType(sharedEntry.Id);
|
||||
|
||||
UnityEngine.Object asset = OdinLocalizationAssetCache.Get(entry.Guid, type);
|
||||
|
||||
return asset == null ? null : asset.name;
|
||||
}
|
||||
|
||||
public void MoveEntry(int from, int to)
|
||||
{
|
||||
if (from < 0 || from >= this.Entries.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (to < 0 || to > this.Entries.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (from == to)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SharedTableData.SharedTableEntry fromEntry = this.Collection.SharedData.Entries[from];
|
||||
|
||||
if (to > from)
|
||||
{
|
||||
to -= 1;
|
||||
}
|
||||
|
||||
//to = afterTo ? to + 1 : to;
|
||||
|
||||
this.Collection.SharedData.Entries.RemoveAt(from);
|
||||
|
||||
this.Collection.SharedData.Entries.Insert(to, fromEntry);
|
||||
|
||||
OdinLocalizationEvents.RaiseTableEntryModified(this.Collection.SharedData.Entries[from]);
|
||||
OdinLocalizationEvents.RaiseTableEntryModified(this.Collection.SharedData.Entries[to]);
|
||||
|
||||
EditorUtility.SetDirty(this.Collection.SharedData);
|
||||
}
|
||||
|
||||
public void GotoNextSortOrderState()
|
||||
{
|
||||
switch (this.CurrentSortOrderState)
|
||||
{
|
||||
case SortOrderState.Unsorted:
|
||||
this.CurrentSortOrderState = SortOrderState.Ascending;
|
||||
break;
|
||||
|
||||
case SortOrderState.Ascending:
|
||||
this.CurrentSortOrderState = SortOrderState.Descending;
|
||||
break;
|
||||
|
||||
case SortOrderState.Descending:
|
||||
this.CurrentSortOrderState = SortOrderState.Unsorted;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetIndex(SharedTableData.SharedTableEntry sharedEntry)
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
if (this[i].Id == sharedEntry.Id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int GetOrderIndex(SharedTableData.SharedTableEntry sharedEntry)
|
||||
{
|
||||
if (this.IsSorted && this.SortedEntries.Count == this.Length)
|
||||
{
|
||||
for (var i = 0; i < this.SortedEntries.Count; i++)
|
||||
{
|
||||
if (this.SortedEntries[i].Id == sharedEntry.Id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
if (this[i].Id == sharedEntry.Id)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a543e4ee8d6d4b629befbccf5aa7b5e6
|
||||
timeCreated: 1706407967
|
||||
@@ -0,0 +1,449 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinStringTableCollectionEditor.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#define USING_WIDTH_NON_PERCENT
|
||||
|
||||
using System;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Configs;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class OdinStringTableCollectionEditor : OdinTableCollectionEditor<StringTableCollection, StringTable, StringTableEntry>
|
||||
{
|
||||
private string currentSyntaxSource;
|
||||
private string currentSyntaxHighlightedText;
|
||||
private string currentSyntaxErrorMessage;
|
||||
private Exception currentSyntaxException;
|
||||
private bool currentSyntaxHasErrors;
|
||||
|
||||
public OdinStringTableCollectionEditor(StringTableCollection collection, OdinMenuEditorWindow relatedWindow,
|
||||
OdinLocalizationEditorWindow.WindowState windowState) :
|
||||
base(collection, relatedWindow, windowState) { }
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
for (var i = 0; i < this.SharedEntries.Length; i++)
|
||||
{
|
||||
SharedTableData.SharedTableEntry sharedEntry = this.SharedEntries[i];
|
||||
|
||||
this.MeasureEntry(sharedEntry);
|
||||
}
|
||||
|
||||
//this.SharedEntries.OnSharedEntryAdded += (i, sharedEntry) => { this.MeasureEntry(sharedEntry); };
|
||||
|
||||
//this.SharedEntries.OnSharedEntryRemoved += (i, sharedEntry) => { this.SharedEntryHeights.Remove(sharedEntry.Id); };
|
||||
|
||||
this.OnTableEntryModified = sharedEntry =>
|
||||
{
|
||||
if (!this.Collection.SharedData.Contains(sharedEntry.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int index = this.SharedEntries.GetIndex(sharedEntry);
|
||||
|
||||
this.MeasureEntry(sharedEntry);
|
||||
|
||||
this.EntryScrollView.ReallocateRect(index, this.SharedEntryHeights[sharedEntry.Id], sharedEntry);
|
||||
};
|
||||
}
|
||||
|
||||
protected override void AllocateItems()
|
||||
{
|
||||
for (var i = 0; i < this.SharedEntries.Length; i++)
|
||||
{
|
||||
SharedTableData.SharedTableEntry sharedEntry = this.SharedEntries[i];
|
||||
|
||||
if (!this.SharedEntries.IsVisible(sharedEntry))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.SharedEntryHeights.ContainsKey(sharedEntry.Id))
|
||||
{
|
||||
this.MeasureEntry(sharedEntry);
|
||||
}
|
||||
|
||||
this.EntryScrollView.AllocateRect(this.SharedEntryHeights[sharedEntry.Id], sharedEntry);
|
||||
|
||||
#if false
|
||||
this.ControlIds[sharedEntry] = GUIUtility.GetControlID(FocusType.Keyboard);
|
||||
|
||||
for (var j = 0; j < this.GUITables.Count; j++)
|
||||
{
|
||||
OdinGUITable<StringTable> table = this.GUITables[j];
|
||||
|
||||
if (table.Type == OdinGUITable<StringTable>.GUITableType.Key)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
StringTableEntry entry = table.Table.GetEntry(sharedEntry.Id);
|
||||
|
||||
if (entry is null)
|
||||
{
|
||||
table.Table.AddEntry(sharedEntry.Id, string.Empty);
|
||||
|
||||
entry = table.Table.GetEntry(sharedEntry.Id);
|
||||
}
|
||||
|
||||
this.ControlIds[entry] = GUIUtility.GetControlID(FocusType.Keyboard);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawItems(ref OdinGUIScrollView.VisibleItems visibleItems)
|
||||
{
|
||||
this.MeasureVisibleEntries(ref visibleItems);
|
||||
|
||||
float scrollSpeed = OdinLocalizationConfig.Instance.scrollSpeed;
|
||||
|
||||
this.EntryScrollView.BeginScrollView(offset: new Vector2(this.PinnedWidth, OdinLocalizationConstants.COLUMN_HEIGHT),
|
||||
addViewSize: new Vector2(-this.PinnedWidth, 0),
|
||||
scrollSpeed: scrollSpeed);
|
||||
{
|
||||
this.DrawEntries(ref visibleItems, false);
|
||||
}
|
||||
this.EntryScrollView.EndScrollView();
|
||||
|
||||
this.EntryScrollView.BeginClip(offset: new Vector2(0.0f, OdinLocalizationConstants.COLUMN_HEIGHT), ignoreScrollX: true);
|
||||
{
|
||||
this.DrawEntries(ref visibleItems, true);
|
||||
}
|
||||
this.EntryScrollView.EndClip();
|
||||
}
|
||||
|
||||
private void DrawEntries(ref OdinGUIScrollView.VisibleItems visibleItems, bool pinned)
|
||||
{
|
||||
for (var i = 0; i < visibleItems.Length; i++)
|
||||
{
|
||||
if (!visibleItems.HasAssociatedData(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int hint = visibleItems.Offset + i + this.ControlIdHint;
|
||||
|
||||
Rect position = visibleItems.GetRect(i);
|
||||
|
||||
var sharedEntry = visibleItems.GetAssociatedData<SharedTableData.SharedTableEntry>(i);
|
||||
|
||||
bool isEven = (visibleItems.Offset + i) % 2 == 0;
|
||||
|
||||
for (var j = 0; j < this.GUITables.Count; j++)
|
||||
{
|
||||
OdinGUITable<StringTable> table = this.GUITables[j];
|
||||
|
||||
if (!table.IsVisible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (table.IsPinned != pinned)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.GUITables.TablesWithinVisibleBounds.Contains(table))
|
||||
{
|
||||
GUIUtility.GetControlID(hint, FocusType.Keyboard);
|
||||
position.TakeFromLeft(table.Width).Padding(OdinLocalizationConstants.ENTRY_PADDING);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
Rect entryRect = position.TakeFromLeft(table.Width).Padding(OdinLocalizationConstants.ENTRY_PADDING);
|
||||
#else
|
||||
Rect entryRect = position.TakeFromLeft(table.Width).Padding(OdinLocalizationConstants.ENTRY_PADDING);
|
||||
#endif
|
||||
|
||||
bool isCellPressed, isSelected;
|
||||
|
||||
switch (table.Type)
|
||||
{
|
||||
case OdinGUITable<StringTable>.GUITableType.Key:
|
||||
isSelected = this.IsSharedEntrySelected(sharedEntry);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
this.SelectionAnimFloat.Move(1 / 0.18f, Easing.InSine);
|
||||
|
||||
FancyColor start = FancyColor.Gray;
|
||||
|
||||
var end = OdinLocalizationGUI.Selected;
|
||||
|
||||
FancyColor.PushBlend(start.Lerp(end, this.SelectionAnimFloat), FancyColor.BlendMode.Overlay);
|
||||
}
|
||||
|
||||
isCellPressed = DrawCell(entryRect, isEven);
|
||||
|
||||
this.DrawKey(entryRect, sharedEntry, GUIUtility.GetControlID(hint, FocusType.Keyboard));
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
FancyColor.PopBlend();
|
||||
}
|
||||
|
||||
if (isCellPressed)
|
||||
{
|
||||
this.SelectSharedEntry(sharedEntry);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OdinGUITable<StringTable>.GUITableType.Default:
|
||||
StringTableEntry entry = table.Asset.GetEntry(sharedEntry.Id);
|
||||
|
||||
isSelected = this.IsEntrySelected(entry);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
this.SelectionAnimFloat.Move(1 / 0.18f, Easing.InSine);
|
||||
|
||||
FancyColor start = FancyColor.Gray;
|
||||
|
||||
FancyColor end = OdinLocalizationGUI.Selected;
|
||||
|
||||
if (entry.IsSmart && OdinLocalizationConfig.Instance.useSyntaxHighlighter)
|
||||
{
|
||||
if (this.currentSyntaxSource != entry.Value)
|
||||
{
|
||||
this.currentSyntaxHighlightedText = OdinLocalizationSyntaxHighlighter.HighlightAsRichText(entry.Value);
|
||||
this.currentSyntaxErrorMessage = OdinLocalizationSyntaxHighlighter.GetErrorMessage(entry.Value, out bool foundError, out Exception exception);
|
||||
this.currentSyntaxHasErrors = foundError;
|
||||
this.currentSyntaxException = exception;
|
||||
this.currentSyntaxSource = entry.Value;
|
||||
}
|
||||
|
||||
if (this.currentSyntaxHasErrors)
|
||||
{
|
||||
FancyColor.PushBlend(start.Lerp(new FancyColor(0.68f, 0.2f, 0.2f), this.SelectionAnimFloat), FancyColor.BlendMode.Overlay);
|
||||
}
|
||||
else
|
||||
{
|
||||
FancyColor.PushBlend(start.Lerp(end, this.SelectionAnimFloat), FancyColor.BlendMode.Overlay);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FancyColor.PushBlend(start.Lerp(end, this.SelectionAnimFloat), FancyColor.BlendMode.Overlay);
|
||||
}
|
||||
}
|
||||
|
||||
isCellPressed = DrawCell(entryRect, isEven);
|
||||
|
||||
this.DrawEntry(entryRect, entry, GUIUtility.GetControlID(hint, FocusType.Keyboard), table, sharedEntry);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
if (OdinLocalizationConfig.Instance.useSyntaxHighlighter && entry.IsSmart && this.currentSyntaxHasErrors)
|
||||
{
|
||||
Rect errorRect = entryRect.AlignLeft(OdinLocalizationConstants.ROW_MENU_WIDTH).AlignMiddle(16);
|
||||
|
||||
SdfIcons.DrawIcon(errorRect, SdfIconType.ExclamationOctagonFill,
|
||||
Event.current.IsMouseOver(errorRect) ? new Color(1, 1, 1, 1f) : new Color(1, 1, 1, 0.6f));
|
||||
|
||||
if (Event.current.OnMouseDown(errorRect, 0))
|
||||
{
|
||||
this.RelatedWindow.ShowToast(ToastPosition.BottomLeft,
|
||||
SdfIconType.ExclamationOctagonFill,
|
||||
this.currentSyntaxErrorMessage,
|
||||
new Color(0.68f, 0.2f, 0.2f),
|
||||
20.0f);
|
||||
|
||||
if (this.currentSyntaxException != null)
|
||||
{
|
||||
Debug.LogException(this.currentSyntaxException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FancyColor.PopBlend();
|
||||
}
|
||||
|
||||
if (isCellPressed)
|
||||
{
|
||||
if (entry is null)
|
||||
{
|
||||
entry = table.Asset.AddEntry(sharedEntry.Id, string.Empty);
|
||||
}
|
||||
|
||||
this.SelectEntry(entry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEntry(Rect position, StringTableEntry entry, int id, OdinGUITable<StringTable> table, SharedTableData.SharedTableEntry sharedEntry)
|
||||
{
|
||||
bool changed;
|
||||
string value;
|
||||
|
||||
Rect smartToggleRect = position.TakeFromRight(OdinLocalizationConstants.ROW_MENU_WIDTH);
|
||||
position.TakeFromLeft(OdinLocalizationConstants.ROW_MENU_WIDTH);
|
||||
|
||||
if (entry?.Value is null)
|
||||
{
|
||||
value = OdinLocalizationGUI.TextField(position, string.Empty, out changed, id);
|
||||
}
|
||||
else if (OdinLocalizationConfig.Instance.useSyntaxHighlighter && entry.IsSmart && entry == this.CurrentSelectedEntry)
|
||||
{
|
||||
value = OdinLocalizationGUI.TextFieldSyntaxHighlighted(position, entry.Value, this.currentSyntaxHighlightedText, out changed, id);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
this.currentSyntaxHighlightedText = OdinLocalizationSyntaxHighlighter.HighlightAsRichText(value);
|
||||
this.currentSyntaxErrorMessage = OdinLocalizationSyntaxHighlighter.GetErrorMessage(value, out bool foundError, out Exception exception);
|
||||
this.currentSyntaxHasErrors = foundError;
|
||||
this.currentSyntaxException = exception;
|
||||
this.currentSyntaxSource = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = OdinLocalizationGUI.TextField(position, entry.Value, out changed, id);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
if (entry == null)
|
||||
{
|
||||
entry = table.Asset.AddEntry(sharedEntry.Id, value);
|
||||
}
|
||||
|
||||
Undo.RecordObject(entry.Table, "Modified String Table Entry Text");
|
||||
entry.Value = value;
|
||||
OdinLocalizationEvents.RaiseTableEntryModified(entry.SharedEntry);
|
||||
EditorUtility.SetDirty(entry.Table);
|
||||
}
|
||||
|
||||
smartToggleRect = smartToggleRect.AlignMiddle(16);
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
SdfIcons.DrawIcon(smartToggleRect, SdfIconType.Lightbulb, new Color(1, 1, 1, Event.current.IsMouseOver(smartToggleRect) ? 0.8f : 0.3f));
|
||||
|
||||
if (Event.current.OnMouseDown(smartToggleRect, 0))
|
||||
{
|
||||
Undo.RecordObject(table.Asset, "Added String Table Entry By Smart Toggle");
|
||||
entry = table.Asset.AddEntry(sharedEntry.Id, string.Empty);
|
||||
|
||||
entry.IsSmart = !entry.IsSmart;
|
||||
EditorUtility.SetDirty(table.Asset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SdfIcons.DrawIcon(smartToggleRect,
|
||||
entry.IsSmart ? SdfIconType.LightbulbFill : SdfIconType.Lightbulb,
|
||||
new Color(1, 1, 1, Event.current.IsMouseOver(smartToggleRect) ? 0.8f : 0.3f));
|
||||
|
||||
if (Event.current.OnMouseDown(smartToggleRect, 0))
|
||||
{
|
||||
Undo.RecordObject(entry.Table, "Toggled Smart Flag On String Entry");
|
||||
entry.IsSmart = !entry.IsSmart;
|
||||
EditorUtility.SetDirty(entry.Table);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Label(smartToggleRect, GUIHelper.TempContent(string.Empty, "Toggle Smart String"));
|
||||
}
|
||||
|
||||
protected override void MeasureAllEntries()
|
||||
{
|
||||
for (var i = 0; i < this.SharedEntries.Length; i++)
|
||||
{
|
||||
this.MeasureEntry(this.SharedEntries[i]);
|
||||
}
|
||||
|
||||
this.HasGUIChanged = true;
|
||||
}
|
||||
|
||||
protected override void MeasureVisibleEntries(ref OdinGUIScrollView.VisibleItems visibleItems)
|
||||
{
|
||||
int dataOffset = visibleItems.Offset;
|
||||
|
||||
for (var i = 0; i < visibleItems.Length; i++)
|
||||
{
|
||||
if (!visibleItems.HasAssociatedData(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sharedEntry = visibleItems.GetAssociatedData<SharedTableData.SharedTableEntry>(i);
|
||||
|
||||
this.MeasureEntry(sharedEntry);
|
||||
|
||||
this.EntryScrollView.ReallocateRect(dataOffset + i, this.SharedEntryHeights[sharedEntry.Id], sharedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void MeasureEntry(SharedTableData.SharedTableEntry sharedEntry)
|
||||
{
|
||||
float height = OdinLocalizationConstants.ROW_HEIGHT;
|
||||
|
||||
for (var i = 0; i < this.GUITables.Count; i++)
|
||||
{
|
||||
OdinGUITable<StringTable> currentTable = this.GUITables[i];
|
||||
|
||||
switch (currentTable.Type)
|
||||
{
|
||||
case OdinGUITable<StringTable>.GUITableType.Default:
|
||||
StringTableEntry strEntry = currentTable.Asset.GetEntry(sharedEntry.Id);
|
||||
|
||||
if (strEntry is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
float strEntryHeight = MeasureText(strEntry.Value, currentTable.Width);
|
||||
#else
|
||||
float strEntryHeight = MeasureText(strEntry.Value, currentTable.Width);
|
||||
#endif
|
||||
|
||||
if (strEntryHeight > height)
|
||||
{
|
||||
height = strEntryHeight;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case OdinGUITable<StringTable>.GUITableType.Key:
|
||||
#if USING_WIDTH_NON_PERCENT
|
||||
float keyHeight = MeasureText(sharedEntry.Key, currentTable.Width);
|
||||
#else
|
||||
float keyHeight = MeasureText(sharedEntry.Key, currentTable.Width);
|
||||
#endif
|
||||
|
||||
if (keyHeight > height)
|
||||
{
|
||||
height = keyHeight;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.SharedEntryHeights[sharedEntry.Id] = height;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8803d1557464e9a9d34713c9c9755af
|
||||
timeCreated: 1704811189
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8f34a530ab34e11b148c6c45d14fd12
|
||||
timeCreated: 1704797131
|
||||
@@ -0,0 +1,23 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinTemplateMetadata.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Metadata;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
#if false
|
||||
[HideInInspector] // ReadOnly
|
||||
[Metadata(AllowedTypes = MetadataType.SharedTableData, AllowMultiple = false)]
|
||||
public class OdinTemplateMetadata : IMetadata
|
||||
{
|
||||
public Type TableAssetType;
|
||||
public List<Type> MetadataExpected = new List<Type>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50bcb1c3eb1c42b3b6a84c57b1c240dd
|
||||
timeCreated: 1707729097
|
||||
@@ -0,0 +1,38 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="Toggle.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class Toggle
|
||||
{
|
||||
public string Label;
|
||||
public float StartXMin;
|
||||
public float StartXMax;
|
||||
public Color StartColor;
|
||||
public Rect CurrentThumbRect;
|
||||
public Color CurrentColor;
|
||||
public bool Enabled;
|
||||
public SirenixAnimationUtility.InterpolatedFloat T1 = new SirenixAnimationUtility.InterpolatedFloat {Destination = 1f};
|
||||
public SirenixAnimationUtility.InterpolatedFloat T2 = new SirenixAnimationUtility.InterpolatedFloat {Destination = 1f};
|
||||
|
||||
private bool _toggled;
|
||||
|
||||
public bool Toggled
|
||||
{
|
||||
get => this._toggled;
|
||||
set
|
||||
{
|
||||
this._toggled = value;
|
||||
this.StartXMin = this.CurrentThumbRect.xMin;
|
||||
this.StartXMax = this.CurrentThumbRect.xMax;
|
||||
this.StartColor = this.CurrentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4e8615bf94265a4a96bf4c23380de7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cf3a6e0f9c8495d843c313b4437232b
|
||||
timeCreated: 1704797609
|
||||
@@ -0,0 +1,68 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationAssetCache.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Sirenix.Config;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationAssetCache
|
||||
{
|
||||
private readonly struct AssetIdentifier
|
||||
{
|
||||
public readonly Type AssetType;
|
||||
public readonly string Guid;
|
||||
|
||||
public AssetIdentifier(Type assetType, string guid)
|
||||
{
|
||||
this.AssetType = assetType;
|
||||
this.Guid = guid;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<AssetIdentifier, UnityEngine.Object> Assets = new Dictionary<AssetIdentifier, UnityEngine.Object>();
|
||||
|
||||
public static UnityEngine.Object Get(string guid, Type assetType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(guid))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var identifier = new AssetIdentifier(assetType, guid);
|
||||
|
||||
if (Assets.TryGetValue(identifier, out UnityEngine.Object result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
result = AssetDatabase.LoadAssetAtPath(path, assetType);
|
||||
|
||||
Assets.Add(identifier, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static UnityEngine.Object Get(SharedTableData.SharedTableEntry sharedEntry, AssetTable assetTable, Type assetType)
|
||||
{
|
||||
AssetTableEntry entry = assetTable.GetEntry(sharedEntry.Id);
|
||||
|
||||
if (entry == null || entry.IsEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Get(entry.Guid, assetType);
|
||||
}
|
||||
|
||||
public static void Clear() => Assets.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5b97d1f7b884ac99cc8ebcdeb3363a7
|
||||
timeCreated: 1704809501
|
||||
@@ -0,0 +1,68 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationEditorSettings.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.Settings;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationEditorSettings
|
||||
{
|
||||
public static LocalizationEditorSettings Instance =>
|
||||
(LocalizationEditorSettings) OdinLocalizationReflectionValues.LocalizationEditorSettings_Instance.GetValue(null);
|
||||
|
||||
public static AddressableAssetSettings GetAddressableAssetSettings(bool create)
|
||||
{
|
||||
return OdinLocalizationReflectionValues.LocalizationEditorSettings_GetAddressableAssetSettingsFunc(create);
|
||||
}
|
||||
|
||||
public static bool IsTableNameValid(Type collectionType, string name, out string errorMessage)
|
||||
{
|
||||
errorMessage = (string) OdinLocalizationReflectionValues.LocalizationEditorSettings_IsTableNameValid.Invoke(Instance,
|
||||
new object[] {collectionType, name});
|
||||
|
||||
return string.IsNullOrEmpty(errorMessage);
|
||||
}
|
||||
|
||||
public static bool IsTableNameValid(Type collectionType, string name)
|
||||
{
|
||||
return IsTableNameValid(collectionType, name, out string _);
|
||||
}
|
||||
|
||||
public static bool CreateDefaultLocalizationSettingsAsset()
|
||||
{
|
||||
if (LocalizationEditorSettings.ActiveLocalizationSettings != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string localizationSettingsPath = EditorUtility.SaveFilePanelInProject("Create Localization Settings",
|
||||
"Localization Settings",
|
||||
"asset",
|
||||
"Create the Localization Settings asset");
|
||||
|
||||
if (string.IsNullOrEmpty(localizationSettingsPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var settings = ScriptableObject.CreateInstance<LocalizationSettings>();
|
||||
settings.name = "Default Localization Settings";
|
||||
|
||||
|
||||
AssetDatabase.CreateAsset(settings, localizationSettingsPath);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
LocalizationEditorSettings.ActiveLocalizationSettings = settings;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 645f3592e85448d7a963218911547f3c
|
||||
timeCreated: 1706732179
|
||||
@@ -0,0 +1,50 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationEvents.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationEvents
|
||||
{
|
||||
private static readonly Action<SharedTableData.SharedTableEntry> RaiseTableEntryModifiedAction;
|
||||
|
||||
private static readonly Action<LocalizationTableCollection, SharedTableData.SharedTableEntry> RaiseTableEntryAddedAction;
|
||||
|
||||
private static readonly Action<LocalizationTableCollection, SharedTableData.SharedTableEntry> RaiseTableEntryRemovedAction;
|
||||
|
||||
private static readonly Action<AssetTableCollection, AssetTable, AssetTableEntry> RaiseAssetTableEntryAddedAction;
|
||||
|
||||
private static readonly Action<AssetTableCollection, AssetTable, AssetTableEntry, string> RaiseAssetTableEntryRemovedAction;
|
||||
|
||||
static OdinLocalizationEvents()
|
||||
{
|
||||
RaiseTableEntryModifiedAction = OdinLocalizationReflectionValues.Create_RaiseTableEntryModified_Method_Delegate(LocalizationEditorSettings.EditorEvents);
|
||||
RaiseTableEntryAddedAction = OdinLocalizationReflectionValues.Create_RaiseTableEntryAdded_Method_Delegate(LocalizationEditorSettings.EditorEvents);
|
||||
RaiseTableEntryRemovedAction = OdinLocalizationReflectionValues.Create_RaiseTableEntryRemoved_Method_Delegate(LocalizationEditorSettings.EditorEvents);
|
||||
RaiseAssetTableEntryAddedAction =
|
||||
OdinLocalizationReflectionValues.Create_AssetTableEntryAdded_Method_Delegate(LocalizationEditorSettings.EditorEvents);
|
||||
RaiseAssetTableEntryRemovedAction =
|
||||
OdinLocalizationReflectionValues.Create_AssetTableEntryRemoved_Method_Delegate(LocalizationEditorSettings.EditorEvents);
|
||||
}
|
||||
|
||||
public static void RaiseTableEntryModified(SharedTableData.SharedTableEntry sharedEntry) => RaiseTableEntryModifiedAction(sharedEntry);
|
||||
|
||||
public static void RaiseTableEntryAdded(LocalizationTableCollection collection, SharedTableData.SharedTableEntry sharedEntry) =>
|
||||
RaiseTableEntryAddedAction(collection, sharedEntry);
|
||||
|
||||
public static void RaiseTableEntryRemoved(LocalizationTableCollection collection, SharedTableData.SharedTableEntry sharedEntry) =>
|
||||
RaiseTableEntryRemovedAction(collection, sharedEntry);
|
||||
|
||||
public static void RaiseAssetTableEntryAdded(AssetTableCollection assetCollection, AssetTable table, AssetTableEntry entry) =>
|
||||
RaiseAssetTableEntryAddedAction(assetCollection, table, entry);
|
||||
|
||||
public static void RaiseAssetTableEntryRemoved(AssetTableCollection assetCollection, AssetTable table, AssetTableEntry entry, string guid) =>
|
||||
RaiseAssetTableEntryRemovedAction(assetCollection, table, entry, guid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7cf7883289c4de29b6e2ae8a072c3bd
|
||||
timeCreated: 1705050052
|
||||
@@ -0,0 +1,438 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationGUI.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using Sirenix.Reflection.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
// TODO: update name
|
||||
public static class OdinLocalizationGUI
|
||||
{
|
||||
public static GUIStyle RichLabelTextCenteredMultiLine
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_richLabelTextCenteredMultiLine == null)
|
||||
{
|
||||
_richLabelTextCenteredMultiLine = new GUIStyle(SirenixGUIStyles.MultiLineCenteredLabel)
|
||||
{
|
||||
richText = true
|
||||
};
|
||||
}
|
||||
|
||||
return _richLabelTextCenteredMultiLine;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUIStyle CardTitleWhite
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cardTitleWhite == null)
|
||||
{
|
||||
_cardTitleWhite = new GUIStyle(SirenixGUIStyles.MultiLineWhiteLabel)
|
||||
{
|
||||
fontSize = 12,
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
}
|
||||
|
||||
return _cardTitleWhite;
|
||||
}
|
||||
}
|
||||
|
||||
public static FancyColor Background => EditorGUIUtility.isProSkin ? Color.black : Color.white;
|
||||
|
||||
// TODO: LIGHT MODE
|
||||
public static FancyColor MenuBackground => EditorGUIUtility.isProSkin ? DarkMenuBackground : LightMenuBackground;
|
||||
public static FancyColor WindowBackground => EditorGUIUtility.isProSkin ? DarkWindowBackground : LightWindowBackground;
|
||||
public static FancyColor Panel => EditorGUIUtility.isProSkin ? DarkPanel : LightPanel;
|
||||
public static FancyColor PanelGap => EditorGUIUtility.isProSkin ? DarkPanelGap : LightPanelGap;
|
||||
|
||||
public static FancyColor Selected => EditorGUIUtility.isProSkin ? DarkSelected : LightSelected;
|
||||
|
||||
public static FancyColor TabsBackground => EditorGUIUtility.isProSkin ? DarkTabsBackground : LightTabsBackground;
|
||||
|
||||
public static FancyColor ColumnBackground => EditorGUIUtility.isProSkin ? DarkColumnBackground : LightColumnBackground;
|
||||
|
||||
public static FancyColor RowEvenBackground => EditorGUIUtility.isProSkin ? DarkRowEvenBackground : LightRowEvenBackground;
|
||||
public static FancyColor RowEvenBackground2 => EditorGUIUtility.isProSkin ? DarkRowEvenBackground2 : LightRowEvenBackground2;
|
||||
public static FancyColor RowOddBackground => EditorGUIUtility.isProSkin ? DarkRowOddBackground : LightRowOddBackground;
|
||||
public static FancyColor RowOddBackground2 => EditorGUIUtility.isProSkin ? DarkRowOddBackground2 : LightRowOddBackground2;
|
||||
public static FancyColor RowBorder => EditorGUIUtility.isProSkin ? DarkRowBorder : LightRowBorder;
|
||||
public static FancyColor RowBorderHover => EditorGUIUtility.isProSkin ? DarkRowBorderHover : LightRowBorderHover;
|
||||
|
||||
public static FancyColor Tab => EditorGUIUtility.isProSkin ? DarkTab : LightTab;
|
||||
public static FancyColor TabHover => EditorGUIUtility.isProSkin ? DarkTabHover : LightTabHover;
|
||||
public static FancyColor TabSelected => EditorGUIUtility.isProSkin ? DarkTabSelected : LightTabSelected;
|
||||
|
||||
public static FancyColor Checkerboard => DarkCheckerboard;
|
||||
public static FancyColor CheckerboardBorder => DarkCheckerboardBorder;
|
||||
|
||||
public static FancyColor DarkMenuBackground;
|
||||
|
||||
public static FancyColor DarkWindowBackground;
|
||||
public static FancyColor DarkPanel;
|
||||
public static FancyColor DarkPanelGap;
|
||||
|
||||
public static FancyColor DarkSelected;
|
||||
|
||||
public static FancyColor DarkTabsBackground;
|
||||
|
||||
public static FancyColor DarkColumnBackground;
|
||||
|
||||
public static FancyColor DarkRowEvenBackground;
|
||||
public static FancyColor DarkRowEvenBackground2;
|
||||
public static FancyColor DarkRowOddBackground;
|
||||
public static FancyColor DarkRowOddBackground2;
|
||||
public static FancyColor DarkRowBorder;
|
||||
public static FancyColor DarkRowBorderHover;
|
||||
|
||||
public static FancyColor DarkTab;
|
||||
public static FancyColor DarkTabHover;
|
||||
public static FancyColor DarkTabSelected;
|
||||
|
||||
public static FancyColor LightMenuBackground;
|
||||
|
||||
public static FancyColor LightWindowBackground;
|
||||
public static FancyColor LightPanel;
|
||||
public static FancyColor LightPanelGap;
|
||||
|
||||
public static FancyColor LightSelected;
|
||||
|
||||
public static FancyColor LightTabsBackground;
|
||||
|
||||
public static FancyColor LightColumnBackground;
|
||||
|
||||
public static FancyColor LightRowEvenBackground;
|
||||
public static FancyColor LightRowEvenBackground2;
|
||||
public static FancyColor LightRowOddBackground;
|
||||
public static FancyColor LightRowOddBackground2;
|
||||
public static FancyColor LightRowBorder;
|
||||
public static FancyColor LightRowBorderHover;
|
||||
|
||||
public static FancyColor LightTab;
|
||||
public static FancyColor LightTabHover;
|
||||
public static FancyColor LightTabSelected;
|
||||
|
||||
|
||||
public static FancyColor DarkCheckerboard;
|
||||
public static FancyColor DarkCheckerboardBorder;
|
||||
|
||||
private static GUIStyle DefaultTextStyle;
|
||||
|
||||
private static GUIStyle _richLabelTextCenteredMultiLine;
|
||||
private static GUIStyle _cardTitleWhite;
|
||||
|
||||
static OdinLocalizationGUI()
|
||||
{
|
||||
DarkWindowBackground = new Color(0.15f, 0.15f, 0.15f, 1.0f);
|
||||
LightWindowBackground = new Color(0.358f, 0.358f, 0.358f, 1.0f);
|
||||
|
||||
DarkPanel = new Color(0.2156863f, 0.2156863f, 0.2156863f, 1.0f);
|
||||
DarkPanelGap = new Color(0.0856863f, 0.0856863f, 0.0856863f, 1.0f);
|
||||
|
||||
LightPanel = new Color(0.761f, 0.761f, 0.761f, 1.0f);
|
||||
LightPanelGap = new Color(0.532f, 0.532f, 0.532f, 1.0f);
|
||||
|
||||
DarkSelected = new Color(0.7076807f, 0.8213042f, 0.8773585f, 1.0f);
|
||||
LightSelected = new Color(0.358f, 0.446f, 0.509f, 1.0f);
|
||||
|
||||
DarkTabsBackground = new Color(0.1886792f, 0.1886792f, 0.1886792f, 1.0f);
|
||||
LightTabsBackground = new Color(0.538f, 0.538f, 0.538f, 1.0f);
|
||||
|
||||
DarkColumnBackground = new Color(0.099f, 0.099f, 0.099f, 1.0f);
|
||||
LightColumnBackground = new FancyColor(0.84f);
|
||||
|
||||
var rowBaseBlend = new FancyColor(0.42f);
|
||||
|
||||
#region DARK_ROW
|
||||
|
||||
var darkRowEvenBackground = new FancyColor(0.2f);
|
||||
var darkRowOddBackground = new FancyColor(0.16f);
|
||||
|
||||
DarkRowEvenBackground = darkRowEvenBackground;
|
||||
DarkRowOddBackground = darkRowOddBackground;
|
||||
|
||||
DarkRowEvenBackground2 = darkRowEvenBackground.Blend(rowBaseBlend, FancyColor.BlendMode.Overlay);
|
||||
DarkRowOddBackground2 = darkRowOddBackground.Blend(rowBaseBlend, FancyColor.BlendMode.Overlay);
|
||||
|
||||
DarkRowBorder = new Color(0, 0, 0, 0.3607843f);
|
||||
DarkRowBorderHover = new Color(1, 1, 1, 0.2470588f);
|
||||
|
||||
#endregion
|
||||
|
||||
#region LIGHT_ROW
|
||||
|
||||
var lightRowEvenBackground = new FancyColor(0.711f);
|
||||
var lightRowOddBackground = new FancyColor(0.611f);
|
||||
|
||||
LightRowEvenBackground = lightRowEvenBackground;
|
||||
LightRowOddBackground = lightRowOddBackground;
|
||||
|
||||
LightRowEvenBackground2 = lightRowEvenBackground.Blend(rowBaseBlend, FancyColor.BlendMode.Overlay);
|
||||
LightRowOddBackground2 = lightRowOddBackground.Blend(rowBaseBlend, FancyColor.BlendMode.Overlay);
|
||||
|
||||
LightRowBorder = new Color(0, 0, 0, 0.2f);
|
||||
LightRowBorderHover = new Color(1, 1, 1, 0.4f);
|
||||
|
||||
#endregion
|
||||
|
||||
DarkTab = new Color(0.254717f, 0.254717f, 0.254717f, 1.0f);
|
||||
DarkTabHover = new Color(0.277f, 0.277f, 0.277f, 1.0f);
|
||||
DarkTabSelected = new Color(0.312f, 0.312f, 0.312f, 1.0f);
|
||||
|
||||
float scalar = 0.925f;
|
||||
LightTab = new FancyColor(0.85f * scalar);
|
||||
LightTabHover = new FancyColor(0.915f * scalar);
|
||||
LightTabSelected = new FancyColor(0.95f * scalar);
|
||||
|
||||
DarkCheckerboard = new Color(0.298f, 0.298f, 0.298f, 1.0f);
|
||||
DarkCheckerboardBorder = new Color(0, 0, 0, 0.5529412f);
|
||||
|
||||
DefaultTextStyle = new GUIStyle(SirenixGUIStyles.MultiLineCenteredLabel);
|
||||
DefaultTextStyle.focused.textColor = DefaultTextStyle.normal.textColor;
|
||||
|
||||
DarkMenuBackground = DarkPanel;
|
||||
|
||||
LightMenuBackground = new FancyColor(0.84f);
|
||||
}
|
||||
|
||||
public static string TextField(Rect position, string text, out bool changed, int id)
|
||||
{
|
||||
if (id == 0)
|
||||
{
|
||||
GUI.Label(position, text, SirenixGUIStyles.MultiLineCenteredLabel);
|
||||
changed = false;
|
||||
return text;
|
||||
}
|
||||
|
||||
Color lastCursorColor = GUI.skin.settings.cursorColor;
|
||||
|
||||
bool isMouseDown = Event.current.type == EventType.MouseDown;
|
||||
|
||||
if (isMouseDown)
|
||||
{
|
||||
GUI.skin.settings.cursorColor = Color.clear;
|
||||
}
|
||||
|
||||
text = EditorGUI_Internals.DoTextField(id, position, text, DefaultTextStyle, null, out changed, false, true, false);
|
||||
|
||||
if (isMouseDown)
|
||||
{
|
||||
GUI.skin.settings.cursorColor = lastCursorColor;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string TextFieldSyntaxHighlighted(Rect position, string text, string syntaxRichText, out bool changed, int id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(syntaxRichText))
|
||||
{
|
||||
return TextField(position, text, out changed, id);
|
||||
}
|
||||
|
||||
GUIHelper.PushContentColor(Color.clear);
|
||||
text = EditorGUI_Internals.DoTextField(id, position, text, SirenixGUIStyles.MultiLineCenteredLabel, null, out changed, false, true, false);
|
||||
GUIHelper.PopContentColor();
|
||||
|
||||
GUI.Label(position, syntaxRichText, RichLabelTextCenteredMultiLine);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
public static bool ObjectPickerButton(Rect position)
|
||||
{
|
||||
bool isMouseOver = Event.current.IsMouseOver(position);
|
||||
|
||||
var c1 = EditorGUIUtility.isProSkin
|
||||
? new Color(1, 1, 1, isMouseOver ? 0.8f : 0.3f)
|
||||
: new Color(0, 0, 0, isMouseOver ? 0.8f : 0.3f);
|
||||
|
||||
SdfIcons.DrawIcon(position, SdfIconType.StopCircle, c1);
|
||||
|
||||
return Event.current.OnMouseDown(position, 0);
|
||||
}
|
||||
|
||||
public static TEnum Tabs<TEnum>(Rect rect, TEnum value, float width) where TEnum : Enum
|
||||
{
|
||||
EnumTypeUtilities<TEnum>.EnumMember[] infos = EnumTypeUtilities<TEnum>.VisibleEnumMemberInfos;
|
||||
|
||||
for (var i = 0; i < infos.Length; i++)
|
||||
{
|
||||
Rect itemRect = rect.TakeFromLeft(width);
|
||||
|
||||
bool isMouseOver = Event.current.IsMouseOver(itemRect);
|
||||
bool isSelected = value.Equals(infos[i].Value);
|
||||
bool isPressed = Event.current.OnMouseDown(itemRect, 0);
|
||||
|
||||
Color tabColor;
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
tabColor = TabSelected;
|
||||
}
|
||||
else if (isMouseOver)
|
||||
{
|
||||
tabColor = TabHover;
|
||||
}
|
||||
else
|
||||
{
|
||||
tabColor = Tab;
|
||||
}
|
||||
|
||||
SirenixEditorGUI.DrawSolidRect(itemRect, tabColor);
|
||||
|
||||
Vector2 textSize = EditorStyles.label.CalcSize(GUIHelper.TempContent(infos[i].NiceName));
|
||||
float iconSize = textSize.y;
|
||||
float size = iconSize + 2.0f + textSize.x + 1.0f;
|
||||
|
||||
if (size > itemRect.width)
|
||||
{
|
||||
if (iconSize > itemRect.width)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SdfIcons.DrawIcon(itemRect.AlignCenter(iconSize), infos[i].Icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rect contentRect = itemRect.AlignCenter(size);
|
||||
|
||||
Rect iconRect = contentRect.TakeFromLeft(iconSize).AlignMiddle(iconSize);
|
||||
SdfIcons.DrawIcon(iconRect, infos[i].Icon);
|
||||
|
||||
contentRect.TakeFromLeft(2);
|
||||
|
||||
GUI.Label(contentRect, infos[i].NiceName);
|
||||
}
|
||||
|
||||
if (isPressed)
|
||||
{
|
||||
value = infos[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static bool OverlaidButton(Rect position, string text, SdfIconType icon = SdfIconType.None, GUIStyle labelStyle = null, bool invert = false)
|
||||
{
|
||||
const float ICON_SIZE = 18;
|
||||
const float SPACE = 4;
|
||||
|
||||
bool isMouseOver = Event.current.IsMouseOver(position);
|
||||
|
||||
ref SirenixAnimationUtility.InterpolatedFloat t = ref SirenixAnimationUtility.GetTemporaryFloat(position, isMouseOver ? 1.0f : 0.0f);
|
||||
|
||||
t.ChangeDestination(isMouseOver ? 1.0f : 0.0f);
|
||||
|
||||
t.Move(1.0f / 0.15f, Easing.OutQuad);
|
||||
|
||||
float value = t.GetValue();
|
||||
float inverseValue = 1.0f - value;
|
||||
|
||||
if (invert)
|
||||
{
|
||||
SirenixEditorGUI.DrawRoundRect(position, new Color(0, 0, 0, 0.2f * inverseValue), 5.0f, new Color(0, 0, 0, 0.05f * inverseValue), 1);
|
||||
SirenixEditorGUI.DrawRoundRect(position, new Color(0, 0, 0, 0.4f * value), 5.0f, new Color(1.0f, 1.0f, 1.0f, 0.05f * value), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
SirenixEditorGUI.DrawRoundRect(position, new Color(1, 1, 1, 0.2f * inverseValue), 5.0f, new Color(0, 0, 0, 0.05f * inverseValue), 1);
|
||||
SirenixEditorGUI.DrawRoundRect(position, new Color(1, 1, 1, 0.4f * value), 5.0f, new Color(1.0f, 1.0f, 1.0f, 0.05f * value), 1);
|
||||
}
|
||||
|
||||
labelStyle = labelStyle ?? SirenixGUIStyles.WhiteLabelCentered;
|
||||
|
||||
if (icon == SdfIconType.None)
|
||||
{
|
||||
GUI.Label(position, text, labelStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
float textWidth = SirenixGUIStyles.WhiteLabelCentered.CalcWidth(text);
|
||||
|
||||
Rect contentPosition = position.AlignCenter(ICON_SIZE + SPACE + textWidth);
|
||||
|
||||
SdfIcons.DrawIcon(contentPosition.AlignLeft(ICON_SIZE), icon, Color.white);
|
||||
|
||||
GUI.Label(contentPosition.AlignRight(textWidth), text, labelStyle);
|
||||
}
|
||||
|
||||
return Event.current.OnMouseDown(position, 0);
|
||||
}
|
||||
|
||||
public static bool Metadata(Type metadataType, bool isFirst)
|
||||
{
|
||||
var isRemoved = false;
|
||||
|
||||
if (isFirst)
|
||||
{
|
||||
EditorGUI.DrawRect(GUILayoutUtility.GetRect(0, 1), new FancyColor(0.06603771f));
|
||||
}
|
||||
|
||||
Vector2 padding = new Vector2(4, 4);
|
||||
Rect rect = GUILayoutUtility.GetRect(0, 24);
|
||||
|
||||
if (Event.current.IsMouseOver(rect))
|
||||
{
|
||||
EditorGUI.DrawRect(rect, new FancyColor(0.2784314f));
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.DrawRect(rect, new FancyColor(0.2431373f));
|
||||
}
|
||||
|
||||
|
||||
EditorGUI.DrawRect(GUILayoutUtility.GetRect(0, 1), new FancyColor(0.06603771f));
|
||||
|
||||
var iconWidth = 16.0f;
|
||||
var iconPadding = new Vector2(2, 2);
|
||||
|
||||
SdfIcons.DrawIcon(rect.TakeFromLeft(iconWidth).Padding(iconPadding.x, iconPadding.y), SdfIconType.GripVertical);
|
||||
|
||||
rect = rect.Padding(padding.x, 0);
|
||||
|
||||
SdfIcons.DrawIcon(rect.TakeFromLeft(iconWidth).Padding(iconPadding.x, iconPadding.y), SdfIconType.Braces);
|
||||
|
||||
rect.TakeFromLeft(5);
|
||||
GUI.Label(rect, metadataType.GetNiceName(), SirenixGUIStyles.BoldLabel);
|
||||
|
||||
var removeRect = rect.TakeFromRight(iconWidth).Padding(iconPadding.x, iconPadding.y);
|
||||
|
||||
SdfIcons.DrawIcon(removeRect, SdfIconType.X);
|
||||
|
||||
if (GUI.Button(removeRect, GUIContent.none, GUIStyle.none))
|
||||
{
|
||||
isRemoved = true;
|
||||
}
|
||||
|
||||
return isRemoved;
|
||||
}
|
||||
|
||||
public static void DrawRoundBlur20(Rect position, Color color)
|
||||
{
|
||||
position = position.Expand(63);
|
||||
SirenixEditorGUI.DrawTextureSliced(position, OdinLocalizationGUITextures.RoundBlur20, color, 63);
|
||||
}
|
||||
|
||||
public static void DrawRoundBlur6(Rect position, Color color)
|
||||
{
|
||||
position = position.Expand(10);
|
||||
SirenixEditorGUI.DrawTextureSliced(position, OdinLocalizationGUITextures.RoundBlur6, color, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12ea4fb9c8db4471801a31e2e0b353de
|
||||
timeCreated: 1704803170
|
||||
@@ -0,0 +1,310 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationGUITextures.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationGUITextures
|
||||
{
|
||||
private const float FADE_STRENGTH = 0.4f;
|
||||
|
||||
public static Texture2D LeftToRightFade
|
||||
{
|
||||
get
|
||||
{
|
||||
if (leftToRightFade != null)
|
||||
{
|
||||
return leftToRightFade;
|
||||
}
|
||||
|
||||
leftToRightFade = new Texture2D(32, 32)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
|
||||
var pixels = new Color[32 * 32];
|
||||
|
||||
var index = 0;
|
||||
|
||||
for (var x = 0; x < 32; x++)
|
||||
{
|
||||
for (var y = 0; y < 32; y++)
|
||||
{
|
||||
pixels[index++] = Color.Lerp(Color.white, Color.clear, Mathf.Pow(y / 31.0f, FADE_STRENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
leftToRightFade.SetPixels(pixels);
|
||||
|
||||
leftToRightFade.Apply();
|
||||
|
||||
CleanupUtility.DestroyObjectOnAssemblyReload(leftToRightFade);
|
||||
|
||||
return leftToRightFade;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D TopToBottomFade
|
||||
{
|
||||
get
|
||||
{
|
||||
if (topToBottomFade != null)
|
||||
{
|
||||
return topToBottomFade;
|
||||
}
|
||||
|
||||
topToBottomFade = new Texture2D(32, 32)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
|
||||
var pixels = new Color[32 * 32];
|
||||
|
||||
var index = 0;
|
||||
|
||||
for (var x = 0; x < 32; x++)
|
||||
{
|
||||
for (var y = 0; y < 32; y++)
|
||||
{
|
||||
pixels[index++] = Color.Lerp(Color.white, Color.clear, Mathf.Pow(1.0f - x / 31.0f, FADE_STRENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
topToBottomFade.SetPixels(pixels);
|
||||
|
||||
topToBottomFade.Apply();
|
||||
|
||||
CleanupUtility.DestroyObjectOnAssemblyReload(topToBottomFade);
|
||||
|
||||
return topToBottomFade;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D BottomToTopFade
|
||||
{
|
||||
get
|
||||
{
|
||||
if (bottomToTopFade != null)
|
||||
{
|
||||
return bottomToTopFade;
|
||||
}
|
||||
|
||||
bottomToTopFade = new Texture2D(32, 32)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
|
||||
var pixels = new Color[32 * 32];
|
||||
|
||||
var index = 0;
|
||||
|
||||
for (var x = 0; x < 32; x++)
|
||||
{
|
||||
for (var y = 0; y < 32; y++)
|
||||
{
|
||||
pixels[index++] = Color.Lerp(Color.white, Color.clear, Mathf.Pow(x / 31.0f, FADE_STRENGTH));
|
||||
}
|
||||
}
|
||||
|
||||
bottomToTopFade.SetPixels(pixels);
|
||||
|
||||
bottomToTopFade.Apply();
|
||||
|
||||
CleanupUtility.DestroyObjectOnAssemblyReload(bottomToTopFade);
|
||||
|
||||
return bottomToTopFade;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D RoundBlur6
|
||||
{
|
||||
get
|
||||
{
|
||||
if (roundBlur6 == null)
|
||||
{
|
||||
const string BASE64 =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAGYAAABmCAYAAAA53+RiAAAFDElEQVR4Ae2dzZIURRSFaQFBDGBBsHGB76Ju0BfxkXwRZaXvIgs3BhEiIT/DYHu+pG+R3XN6mDa6uZuTEacr61ZWVcb3kVXFaq5dSwuBELg6gVUN" +
|
||||
"Xa/X1a1tHWO7G8bU8RqfrSdQYNnuhjPq+Dh7tXqP9cbY2/4p4J+pTK5PqRrbGqdu2iUEAP/vlHfqV6rO6VuCdsUAm5SQm+p/vgl9wjklSN3RIqlIvN/OkAv+uQ693eRMW8I+khhDW87bFcNBoFO/pdxW7ihfbML+" +
|
||||
"LCdCBOSSVqulpLzW2FebvNSW/TcKxxG0tFnMvFKQgpC7yn3l3qZPreTkcSYYH2klhpWBBGS8UJ4r/AOHIY1xNZbtWBlsqzGQE4CPlAfKQ+Vb5XvlkcKjLe1wAjy6nio/K78pcKbxGKvHWT3SPrzA9VWGFKCzKlgl" +
|
||||
"SPlK+VF5rKQdj8ATXeon5Q/lmcIKYjWd6atsyKmlpNqQxBcYcninIOcbJVIE4cgNpjyFYAxrmMN+eWc7MSwxBvMo+0FJOw0BXg0whjXMLxWDqHrH8Eh7pKSdhgBsYWw/pnZXDPt8qZUclljaaQjAtqTAHPb2Ucbt" +
|
||||
"OTjLoZZ2OgIsgJIC96XNO9iq/8uUoGVgOichUJzZFv9xo1nMfOetQfOB9I9KYC/nfWKOevdc7HACTgwW0z4tgQvMnZhPO6XczRKIGIulvxgx/Q7sDCLGYukvRky/AzuDiLFY+osR0+/AziBiLJb+YsT0O7AziBiL" +
|
||||
"pb8YMf0O7AwixmLpL0ZMvwM7g4ixWPqLEdPvwM4gYiyW/mLE9DuwM4gYi6W/GDH9DuwMIsZi6S9GTL8DO4OIsVj6ixHT78DOIGIslv5ixPQ7sDOIGIulvxgx/Q7sDCLGYukvRky/AzuDiLFY+osR0+/AziBiLJb+" +
|
||||
"YsT0O7AziBiLpb8YMf0O7AwixmLpL0ZMvwM7g4ixWPqLEdPvwM4gYiyW/mLE9DuwM4gYi6W/GDH9DuwMIsZi6S9GTL8DO4OIsVj6ixHT78DOIGIslv5ixPQ7sDOIGIulvxgx/Q7sDCLGYukvRky/AzuDiLFY+osR" +
|
||||
"0+/AziBiLJb+YsT0O7AziBiLpb8YMf0O7AwixmLpL0ZMvwM7g4ixWPqLEdPvwM4gYiyW/mLE9DuwM4gYi6W/GDH9DuwMnJjxZ8vt6BRPReACcyfmVDfPdQ8gsE8MBi9YPOC6GXo1Ans5z2JqEH9PvnK1y2fU/yVQ" +
|
||||
"nNkW/3GtWQyFGniu/tsxIj+nJABjWBf35V6zGIwxoKS8Vv9sGZnOsQnAFsazHByM5sQwkBNeKk/HqPycggBsYVxy6nE27rUr5p2qiHmlvFB+UdJOQwC2MIY1zGG/d8VwkCXG4L+VX5UnStpxCcAUtjCGNcy3xCx/" +
|
||||
"fHm9XtO/odxSvlTuKw+Uh8p3ymPla+WmknY4AVbF7worBSl/Ks+U58o/yhvlfLVajVWzK4ZHG3JuK3eUuwqC7m361DiGHMYu56ufdpEAkHl3zO9tHl+sFITQr/fM+DorMUioVhdhSWGPVhfF6F9KSeG8iBGEj7Ri" +
|
||||
"On/p8ugiJQTWMN96+c9idGw0BnAhLsoJ9THAKiElZf5wyMoRmKnBrho8iyksCe8UQr+kqPuhLUD1jqlq1QBPrk+pGtsap27aJQRq1ZQgRFSqxulDgB5l41IL3EnMOKCfOsZ2N4yp4/TT9hOof/Fsd8NZdXxcocSM" +
|
||||
"nfyEQAhckcB/Z2rwteNGzXsAAAAASUVORK5CYII=";
|
||||
|
||||
byte[] bytes = Convert.FromBase64String(BASE64);
|
||||
|
||||
roundBlur6 = TextureUtilities.LoadImage(102, 102, bytes);
|
||||
|
||||
roundBlur6.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
CleanupUtility.DestroyObjectOnAssemblyReload(roundBlur6);
|
||||
}
|
||||
|
||||
return roundBlur6;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture2D RoundBlur20
|
||||
{
|
||||
get
|
||||
{
|
||||
if (roundBlur20 == null)
|
||||
{
|
||||
const string BASE64 =
|
||||
"iVBORw0KGgoAAAANSUhEUgAAAMEAAADBCAYAAAB2QtScAAAgAElEQVR4Ae2di5bjOI5Ep3f3//94t1fXruuMhEGKsmVnVlXiHDkCgQdBiazqeZ35z39+7OcN/LyBnzfw8wZ+3sDPG/h5Az9v4OcN/LyBnzfw8wZ+" +
|
||||
"3sBf/Ab+6fb+77//dvKP9vwbaN/3pO3Ph5i8nEdD//zz+TP8z6ON/tK6z2/v9S/h2fV+LtHCN/q5BJ9f0rOH7nO3r/f29vNzSbZv9Ddfgr0D8vVH+PUTdO/gr7sYf8sl6D7264/Y77lC967+6IvxJ1+C7mP+nsfy" +
|
||||
"66fOd/nHXYg/6RLkh/rKY/OuOb7qMNb9fdUcp33jP+ES1I9y2suJRu9YI5ZbokdmeuVBdY5XrrH0Qh5N+l0vgS/+0X2P6l7Vd7Teu/TRvs48uLnGmX1f/o5+t0uQL/rZl3NmrzrLK3uz1lmHrJvzjN72PaNXfben" +
|
||||
"+7/LJfClPvsCnu3zbP2z81u/OscjhzB7P1LvjKC9nu2TPU/n3/0S+BIf3fij9Y/WzeZ8tOczB2i05mrPWr9aV9+DfR6tr/1O9b/rJfClPbLZo7VH85npkZpH9vLoWnuHrZt/r6bOspJf9+y6j9TWXqf53/ES+KKO" +
|
||||
"bnK1bjWP9Y/k1nmfqa290l85QKO1Z7W1ZpbLPObv5eXscmofqbP+VPxOl8CXenSDK3Vn5TDbSq+jeziSv7p+d8i62i6v7nOUk3mznG5/znK0ruv1lPZdLoEvZHUzK/l7Oc/GnXWvj3mvxnqYRnPt5dU4c2evLr6a" +
|
||||
"070Deo96dvmna7m5W/M3/u8J2vVvg/Rkr2YWf0Usp5z1z7yz+OrhmeW9Isb+Zn1H+3+kZtRrqNf/PUH70d50Cdq1h5N//tOops16jWJHddYc1RyZp+Y+4q8ellneKHZUZ/5RzV6s2/usV5d/WPsul2D1MLHBWe4o" +
|
||||
"dkQ/krs3T36QUd/MeYSvHpJR3hH9SC57GeXvxep7mPWpuYf973AJjhyOWW4Xe4fGS+/WyY+xF8/cR/jeIRnFO/0dmnvs1jJW8UhurZ36X30JVg/HLK+LrWg1p/q8uKpV35c70rse1pyNs0MyilW9+sxYtT2/qxlp" +
|
||||
"6FjteVXvf1fz7isnyldegtnByZFHeZ2+omVOctY86nc1zl57qXe4l3vk449yO71qR/y9XPZZc0baTCeW1vXM+GH+VZdg76O7kVFe1atPfWrJz4rVPvhYXeuqXn9nscxb5bMD0cWqNvPPirGXWa/ca83LWPLVvKwZ" +
|
||||
"8q+4BKsHoctb0TInOS8h/aN8Vu8Lzp4zzVjFWn/kY3e5e1qNp3+Us5dRTY2578yfacYSu9qML/N3X4L6kbtBRzlVn/kZezVnD7lG57vPmqf+KI4OQtVnfsZezdlnrtH5vouap564kpP5LX/nJVg5AKOcqqefnE2m" +
|
||||
"LxePxPdqaq8Vnxwt+6ut4OzD19jMz1jHVzVmNldMrfIVnxws+12V+9+VnPuqUN51CVY++Cin6unv8S4+02YxXptxMTVfa8a6uHl7scyTzz54jc18YyL95WKnzWJdfmozXmP4Wq6pVnElp9bc/O9yCerBccDUkxNP" +
|
||||
"Xy5mXK3iSs6spqtHw6y7evf+nm684uhjV33kp95xtT1krkdyss692aeLdTlqidkj9SX+jktQD0Q3WM2Z+RnruNqrkPlr79Qq7/yRhr5n3QevWvodn2nGzkb2Zc8Zr7HOR6uWvWts6r/6EnhYZkN0Oant8S6ulpic" +
|
||||
"eTq/00a5qa9y8jDXuXrHf7sPntoeN76CZ+Sww9ontRknhll/9frflZy7ynoJ3v1fpe4OQ2p73PgKdjmrGi+O3C7fl1pj1hjv/JXY7MPWWPpykbXkiXBm75CaGkM7anu96ec6lbtWxtVegix0Zw/+t0jbXtG8i6e2" +
|
||||
"x413uKdlfMQZlVjGZxoxrOandkn49WNeaivcA5y5qclF8uSJyc3Z0zI+4rNexhJXOXmY6169+9+9+F3Fq/4m2PvAXTy1PW48MTkbxU+t8upnzSxm3gpmTuX4mGtdvfFv93FT67jaDDPWceZTTz6alNy6J7UO6ZN9" +
|
||||
"R9z1Mq6WuBfP3Ja/+x+HHILBtT1uHExOfdUybqzTsnYvnrnyGWascnzNdfVFD6C+mHrH1TpMrXJ8ZgF90mf96qN1Zq+MqSUSt+eMZ5+X8TMuAZuZWY1X39rU5YmrvObh+7CWPLHqM9/YCmYOPI31O+OwdJa6fAUz" +
|
||||
"B77im8OMWeNc6vodUuce5YnUjPpUvfp1vb14zf/kn3EJPjUsDsPNzLhIrjxxxmsM38d++h3OcmosffkMMwbXmGNmHJZqqclnmDF456uDzJS+POfInNST2wut42ogZk/xqt7/7sXvKxaVZy8Bgx2xzE9uD7XEGSdW" +
|
||||
"42pHkPVn+TWevrzD1OCY81698a+HxIz05R2mBu98dZE15HvoPDOkh/vsuBqYRo1a8swZ8aP5tz7PXoJbo4b4Egyl33G1xBknlg/rpN/x/1rIsW7Ur+r6MySG0fuIeSCs0Z8hsYzri/SS7+H/ufAE2RN9qqG5346r" +
|
||||
"JdIj+yWvMfxT7JlL4AafGcQeHaZWOf4zz5HLUNdhv6mlL0+svPPR0jgYaenLEyvvfLTVx8PPe1qpyVmTU8u7wjqulnjNfuyXteh1yJ65BLOF3Lg56cvFmpM6XF9+BEeH/aieazJv+nAsUZ565fh7lh+0cv1EuA+9" +
|
||||
"5SPksHexUa2Xg/iq0d/3Acfw1dUugV8/xnGTd/6vksfh0UvgprqVj8YyXw76sIZ8BesBP+q7Rq1TB7H0q2b8kvgrt+NqHebh6Diaulykn7xiHnzmNl719MnB551k/uYuGTW+Iwr0Qcw5xNQuCeUn80ro1qvqQ//R" +
|
||||
"SzBs2ARy84bVKhJHU09ffYT10KZ/lLtG1qlVrDPqd4iG0WNmHg5z9DtES12/Qw4ya2fMw44ur/3yAsAx3g15+mgzs6d7Tx/uXGL26rSMP8VffQncMEMmz6HVQbn5ajOsBzV9uUgfecWMuZ45+nuYc8tBjFotuVqi" +
|
||||
"BwSt42jq8hVk3czjAKvJwdp7ky4aMd4JcThW/as6/rW37wDfGWpV6slr3lP+I5fA4buFZzHzzRHRK8dfefKQdlxtFVnT3Mo73xndQ+cTw4hpydUSPSholeuDPubpix5ofdaVE9OXd0g+lkge7wkNjuHLL8LOj/2c" +
|
||||
"gXS5OGsxy5nF7no+cgnumgwEBtGSo+mLavipoWvGOuwOLpp6h51G76qn1q3dacysLgcx9BXzkJArBytX65C9oHM4QXw5cxiDo4sb/bRO+uTZBz15tzfWqJZ5xtHgojXpJzf+NB69BAwxslnMmi4HrepqifRIn5eP" +
|
||||
"v4KZs8K7vqnlHB3PWeUgRv6KeTjIlYOVq3XogWfPctYnN7FeAGJomOvh0wdTA9UTL0m/8rr9Wk+e8dTUq4ae5h5Sk89i5lzw6CX4VLzouEnT9UE5Mf1ncHbAa2zmMwNxc/SdLXW1xNyPPLFyfC0/vDyxcvz6cCDR" +
|
||||
"mLNy5iSWCCfPPcAx9av3cfiJ25scrGJql4TBD7Ng1uds18g1Zp7aaXjWJXADDlZ99NQqT98e1hCrj4cwsfLOR/Ohp1xMTd5havDu2eSbLgcx8meWH1wOVq6W6AFFk4P4zo0PV3N+9fS3tJuRr9kbX56ITp+0rFc3" +
|
||||
"xxh+xzPfOFrmm3MIj1wChz2yQK1JPzk98esz0jOPA6zvYRbR5StY89OXg5WrVcz55aBGflp+XHR9sHK1ihxENTmYB9Q5yZOL5I2M/DRyqePdyomjYSLcteBp2ZN8/eTkVz97PMWPXILVhXLj1nQaMfRHH168tSsH" +
|
||||
"fDWHnjVXrUNnGOHW7jYnHCN3Zh4EcuD68hlyGImD7CPRg+o+0h/Nnzr5ndnH9dyfSE3yrgea+8w4dVXvtKyRL+WdcQlWNudQIPkrNZknB3nR+nlY1cSMjfh//+o3iruecf3EXE8OYp1/jVx/zVOrH1sf9CFXDnIA" +
|
||||
"O18drIc0tTrjlj411soa3o1W13F/1pAHn1nWzPIyRs1e38z/xM+4BJ8ahuNmKpqC/ujDi6+1HtQZdoe+07oerKcudwZ0ecUtdIvBMXJmlh8Uri+vyOFTk3vQmU0O1vn0t9DF9EczOov5tafr2Ye87JXcHonZn1z8" +
|
||||
"ipn/NF+9BHuDO8he3l6cPuSYJ+/QA7mKedhHfLUX85Cb2M2Y2pZ+21fl+FoeAjm493AYyUmE10OaMyXfUj+9e/zOnKmLodX10FgHozb5RRz8kDdbay9u29281Utgw0fRjVMPTz81dXOO4ugQe+hF8uSitdVXT2Qu" +
|
||||
"/MTKnT33Jwc18rD6wfXBytU88PjyRPjo+d8t5ozOIG6hu2+EhjmLPHt0nDz7ivSQ2wfE1F0HX35JOPvn2UvgwHUudZF4cn201NNXV/PQ6Yvd4UzNQ72H1JhjffXRWde4PNG5Km5lt70Sm5kfPRHePXnoiXvomVEu" +
|
||||
"1oOfPvM4l4hWLWdiDQ297tkZ0I2L1Nkr11Mjbl3y1NC1kW58iM9egmycG0k9+SgH3Zh8hh5C0LzURtxDvYr2Md/11NPPOeQgpi9PhKd5CBIrx/fwJ/ewG9PPw46mz7rOCO8s1ybe+fTgXWjk2Ne9p09e5tjTepD8" +
|
||||
"Tj+ak/ktP/MStAtsops3ni9FnjG4NcZFD58+mJq8Yh5iOTji1hvX79AZEnM+ufvCXzEOgIdAXjEPOzEPvejaYB5+fC8CiHVzuT5xeSKcd4LBXU+NNdVAcxI3eXdta8k93VYuAQN0tqdnPPmolzmJ8NnDyyaeh7P6" +
|
||||
"xrpD7yGvMWoyZo8RumbOSi4+lvpV+YjpixwQDe6DBudgqaXvwR9hHvqci76Y2tX7/Ot6qHL2B8dA/dxrx8lFFzd66wOvZi66XJzlZmyUf8lZuQTZ7BnOINXQ1OWr6CHrEI3Hg6yv5qE33vnmJmaf5MyMn1j3sYUv" +
|
||||
"cXQtOZqHSq4P1sfLkLh6AfJCsBZWZ0HLNfGx1NgzfsW69+rTx/WoT05MQyf+UjvrEriJOmzV8fMx37xE88iRi/XApQ/PJw+4h34WN2eEWStnLniis1bc0m4fHd6ZHx4cPXn4yXnmAjhDrqWWmHE5+4ZXzH3TI33y" +
|
||||
"8RPNATXimvn64kg3votnXYLdhSYJbAJLlHc6sXzy8MH3nnopRj59Hr0IzOdczrpJt7nhGLG0/OhwfTno4Zfrd5cg/8Rnrdk//+cc8lx3xtkrcfeaSC984pgx8xOvGW/+PfsSsEFMrPwS/PXjy8icWmdOh3nI4Eee" +
|
||||
"0cGvOj1XLwIzOpNY5x7tFV3zsCTC88mDj756AZzHy+CaFXOtVe7+yXedDoljxMwV0Y3DNXPx5aI5D+PeJWChzkZ6l4tGfn3MtVdizU0/D1jyzIETq4+HXF1/huSuXATXTKwz4WPi1bv/9SCA3bN3Cbq/AVhz9fCz" +
|
||||
"X2y0drcv3hP5xJJ3uWjmJm5y+27IWTV71/yR/p+9S1AbHfFZdM/MSYQfeTzQFemRmgcZzUOfXK3DzOt65lry0R54J8Qw8epdDwbcjw52T14CODOBHn76yhM3eWisw94x18SXg66VWvLRnkc6tcQSN3do5g4THgmc" +
|
||||
"cQkY7BGzrmLtRfzIk4e043xYdTm491CT+faoyKxos5m38MXISeMwaHm4Kq+XAN/18jKsXAB7s7eOsxf15Lmma8/QfSWST++KmbPCrV/Jvcs54xLUpgykJVcDq64Pjh7riNdDhu9jXH+E9UDvXYIuv+vt+qN9oGPi" +
|
||||
"1fv45VBgHrwOu0uAdvQCuI6YF4G9sbaYnHVSx3e/6u5PvUN6ooNa9Tt9lGPuITzzEjBYZ+j1MS9rzCEmN56+nJftUzV8YqJ5o4OcOnz20Mv85LmWHOyeTb7oYDUPBNg9HkAPHjPA/VOf9eTgzOjPXmZIf+K5bmru" +
|
||||
"NWete97KP72H9KnTT/5LvoGxm7AR1un0zNnlZ16C3cVKAhvAxKv32a8vc+bzYYzD9x4Pcodos4fe1nXrMAe68yRu8m3P6Gl+0ER4PhxGfNDH/vhnXABmZw33JhdZhzWJy51hhlv6xcihl6Yvqr8FH7kEDLpneznG" +
|
||||
"E+H1YZ29HOJ54Pxw6vpiHl55h2ijh17WJM814fryTbrtET4yDoiHRM5hg7OeB0/uwWcdTLx697/0Yf4O3Y9r4ctZF9913Z/zuM/ELf02T+rJ6Y+fSF1n5nUxtZUcc1/67w7dFimEAVeMvKMPH8caPxa+vEMPc4do" +
|
||||
"o8de1unnes5ScWt7OxjwNA4CBuZDf3wPHL6c/nkRZv8YRA9m7tA9EJO7jr5rqte97flb612jBzO8xWZ/EzDIns1yulhqcrB7WHsvhzgfo6Kauh9whB7kPPDkpl+58a6n6ybCMVCuD+ZHh+vLOXxwe3oY7Qd6ETba" +
|
||||
"GvXso8PcB/H04a6njq8u5izJt9TbnlNP7t5AjJj8Igy0ldg0Z3YJLDyCDJ6WfnJzOq3GyKl5ajP0YyWan5qcwyEH9evhr3rWJGctfNcUN+m2H7Q0P3oinIdeefDsl5i9KqcHs3eYc7sOfauesVy38lzbGBp8ZMSY" +
|
||||
"LS215ORUP+sO8bMuAQONjFiNp5+cHpnfcfONJfKR0q+8+6ip5QFH15frg8mzh5y14XUGfEy8eh+/HgSwPtSgjXp+dPlg9mBeeEXn7dA//bv1yO/irJz56VeOj7mvyvVBZu8sa7v4rnbWJdhdaCehvjTS0bSM7/Hu" +
|
||||
"Yz6i5SGX0wfuo9/1Z070bt5N/rQ/fM2P7eFNpBf+ak9ymRWTg8wldrOvaN0F6OZC0yo3n1m+zL7iEvgixG7zxnxJZ+LeB84DX3Pz8BPL3OTMSzwx98Ce8TvzQID5eOhE+9Ue1qNnPfPgO7ccv3vsfyZuSw33bYy5" +
|
||||
"WBN8i73iErCBkdVY56uJtRe6Mfke5kc2N7URz4Ndub7Y9ci15OwHjolX7+PDewBAHg8+nBr8tNqHGLnMZg85c6J186LRiyfjanu4ld3q4dWox+xz9a6/aMylVV8dnMUyb4m/4hKsLMwmNLhPanD1xKpXP3Ph+WH1" +
|
||||
"R5p6HgD47KCbmzmjdXI25h6ZB1ekDu7h7/p4gKwRPfz4zkofefaCdzpazUt/C3+KV99cdRBTB50/+SXp1T/vvARsbsXME7MGTV0+w/rx0vdjp0avqqdfuQdfzLi9EuFYxav6cRA8EB5kDq0atV4G6xKtSWSuPPj6" +
|
||||
"zlbnVgd9yJHPkFmMw9PQMfHqjX/Jc9/jrCcjr7oEK5vscqqGn4/bVcOX72F+xOTU5SHo+ErOrK7O5txgNT96HmLqOcTiSo31efjRRnM6I/GOq42QmYzBMX3xql5/0aqhuf8a01/JMXcJj16CbvCVhbLuKM/+1Pqg" +
|
||||
"y49g/cjp1z55YIilv8KtqX2dHazmIfAQi+QZW63xAlDHvF6kOo97UceXH0Hmynz8asS1yt0fesetW8HsMc0/egmyWW4gdblxUb0i8cyRqydSW+Ojflm3wj0Iidap4ctBfTFjNW4vEBOv3sevHx/MhwxjH9lXjbWI" +
|
||||
"ifC8AB7+Op8z5myrPGeAWycX1UV1EFPv9nbNuOYQJ3clz7olfOYS1AUYsFqn1Zwjvv1EauH5pJY8c+B5AJJnnofG/JpnXL3zrbVvzgSvxkfODw73QIvWEGNNLOtcM2vJ8zI4i3n67kM/kTX0k6emngg/w1iH/aR1" +
|
||||
"WsaX+JmXYGVBhsbEq/fxqy5+RO5ryBk91I1iz+r1oNNPLXt7oMSMwTHx6t0ffnV6eAHyIKNjHA564XsZMq+u/Yy/LTF9t8S1uj90NdFcEd391ENvzqn47ktwZHheRj7Wjl5exs1ZwVxjxD3Ionmdj6Ze0TpmhVdD" +
|
||||
"ywOQB5peXgTrzKWOePXNX70Q9HWuGRojv7OMw/Pp8r9U+06XIF/c6KWY40s1T7/GU38VHx30kZ4zOv8e5gXIA+3BF1+1x9qXeVNzfjXj6iMk/8vtjEvw6EaybsT3XhB1WUu+/iNov3ege3NO/hTH8OUX4dePeWfP" +
|
||||
"RvvsfcT/Ndql3h5qM8zcyru9z3oRo8cjdZe+o0uQg10SX/TDOqtrmSd2IxlbQXLyoV/6yY2JGXuU0wujfsXMW12Pnns15tSe6itITrVct8Y63/UfPshd04HGWp/WGV2CQf3bZF+iC674Ncda0TiYnHhq6Wde5sgz" +
|
||||
"vlc3qqEOsxcfSH4J/PpBM2YvQuaqrfrWZv5IQ+/MNTNmP7U937wvw3degvoyVjeddZXjp0ZP/YoZg2vm4cPTr9osPqtb6UOO5mHH908t19YnpjZb2xzytarVevJSk1es/YyP6s1fRfrlflfrDuXxL6i+k9WXmP7K" +
|
||||
"nKP81OWifTs/tcrxU6OPmpgaHMvYUd9a8dLw148aqFWePjkjP/Xk9u1qM9Zx+mSv5F3+27SvuATv2LxriKMXalwkD179rM+Y+Ymz3IzVmtp3lmvMGrHqnU9u5stFayoaF2v8TP8da9zm/YpLcFv8zeSMF/tMD2qz" +
|
||||
"PrmvIrWab84qZq/Vmpp3Ro/a89v5f9Ml+HYv/2eg7/EG/qZLcMa/wHqmB7VZn9zTkFrNN2cVs9dqTc07o0ft+e38r7gE73ixriGOXrxxkTx49bM+Y+YnznIzVmtq31muMWvEqnc+uZkvF62paFys8TP9d6xxm/cr" +
|
||||
"LsFt8Ybk5uHpN+l30ig/dblok85PrXL81OijJqYGxzJ21LdWvDT89aMGapWnT87ITz25fbvajHWcPtkreZf/Nu2d/zkBm37kX2jly6ocPzVenH7FjME18/Dh6VdtFh/VuWfj+HL6VzMGysmpfmqZl3rl+FjtVevN" +
|
||||
"uST/yk+t5tsv9RG35wpmj5X8h3LeeQmODFg3v+LXnLqecTA5eamln3mZI894rfOwm0NcM4ZfLwla9k9eY/qiuSt+5shFZxbRO8v1jNeaPd+6L8PRJWBwP84rh+te4mg9X6bY5RlbQXLyoV/6yY2JGZtx88E9o482" +
|
||||
"67kao5c9RzXm1Lj6CpJTLdetsc53/S52tuZst76jS3BLWCA0feTCZF0OlnxveXJrvv4jaL+zkPmdI/eC5jurcX3wHQ9z5ZpHfHIx57x6+7+uZ60Vqaut4KN1l95nXIKVIVdyVjZiDiint75a+q/m/vf7RdfD5994" +
|
||||
"EJlzxbo90ANdzDU63firkH1kb3xMTX4RJz/kf7l9p0tQX4YvVDS+9+Iy39wZmj9DD7JoLj5/oqfvnHkBzCPXhxr/NrAGDbNfIj3wQZ8urpb5anu4tb6ssYf0mVnG65qzui+JvfsS8EI8NPUA8AJ8eWK+lKrhjx57" +
|
||||
"jeLP6BwuD7J7QcP06Y+WF4E4Rsx6eDVnQ5ePDjS6MXL1U7PHWZhzdT2Ja8SrqYlH4zX/af/MS8Cm+LhpnZbxo9wXJ1IPzye15JkDz4OSPPM8VB5m9gc3h7h7BvE1a0TiPtRbZ75IDHMN0RmdaeRnfs0xlmgOWvLM" +
|
||||
"gWNqyVNTT4SfYc6QvTot40v8mUvAAKMPyeLGxdFAxHk0uXoiOTVunZj5RzgHoD4eeHT22h1oY2A13w+YD3nGak3dn3ugPxzMR000lj48fXNAY0dxK/1k1iPCMbVE9UtC5Oh3mP26uJp5+kt49BKwyOjjzRbMuhm3" +
|
||||
"x2gz6D7kyo9gfngPw6jeOHvuLoDvQmSmNHUwH3KMZT6cWbA6k3M70wrSI/NqT31z0pcfwTo3fjX6aUe5dSuYvaf5Ry/BtFkEGWD0kU3rcurg+PlkrbkZn3E+tPHkaB6CiuwBbXQB3KO4pd6Mvv5NApJjXkWLqMES" +
|
||||
"na9inXXkWzeKo5Pjk35y4yN0buJazVUHM0+904yJKznmLuGrLkG3OMP78bu4mpsU1UE0dfkM60dMH56PfVLz8KN5iBM3uTV6UYuRj5918Jk5S0VnQ5fzf9YHF9UrZg0xe3d55prT+RlLvrW+9YankYeJV2/8u5o3" +
|
||||
"7rAQeeclyHHYnAcB7mOOm1dPJGfmZwyeH1y/aqnnwSePOf1/hewOsvvY0m5zeQHoSxzf2o3e9p616ORjic4GyuvBnfnd5cg+9hXtpW9u+pU7s3r1q04cUwe15GovxVdcAjZRP66bqLHO9yWI1oroxuR76IcFzU2t" +
|
||||
"cuZHy8OffAt9MudRdA36cAHw4T4bnb4j4vYQnT3RGUF5HvoRN7/DXM+42h7m3PBq1GP2uXrXX2Nq1VcHZ7HMW+KvuAR7C7MBDoPY5btJ8OzHDztCDztx5hThxDT8as7qwRfJzYe6rh59tndmId7NXg98+jV/FjPX" +
|
||||
"vZyJuT94tdx7jb3M/4pL0G0mX7RxXwh+xve4H/FR5HBSy0GBg5iH+Opdf52xm4l8dOsSqcbvbNaTuYh3e/Ngg3L3oS929Ue1bs8jzX26N/zMNf4leNYlYEN7HzXjmZ+cl+DLGXHiGTMf5EP6p2/q8r0PzSFhzopq" +
|
||||
"W6g1+ydSgw/mQwN8TLx613w4dVj2gzO/2O2FuT3oyclNPf2uj1pdP31y0pdv8ic9/crxMWq15GjZ15zEmp+xJX7WJXAxBsoPm37yUb466OZAuXG1GfohE70gqck5JMzeoet22M1AT9YS6et7SU4/9dyjPYnL6QVP" +
|
||||
"hOeTBx2eD3kZTz97wHPNUcycDrcWNzOOAB9ZF0stOT2qP+q7q88uAYv4gUaNZjldLDU52D2siY51cTU+Uh44P9rswLMv80AOB1qHm9ya6+f/OySa88BdB8yHhvidUYfZv6Jzo8vdg34e/uSZh56+tSN0DuOun2hO" +
|
||||
"Rfcj1ji+sV/09u31azz1vZi5rqN/wdkl+JR4osMgowOQy3Qvak/jA9XD7wXx44Gsr98dfOLoI2OOPPzyuj59WB/kwZJflftf90lETu/k+qAHOjla99Sc9OHdw7rqOYP8CG6tdo1+b7NHLgED+kFHg+7lGE+E14f+" +
|
||||
"aFiNpc8Hmh1+5vUjcjD05R1uaUPrZmL9nMHDz7oefN9bRRfKvmi5Rzn94O6nIntBA0eP8Q5Tg+eT69Z59CtuLXa/Yc3BHxn993Q2/NkAABGMSURBVGwl59bjkUtwK36SMCiHQbRdbgC++vCx8hDi0z8xeXfwyUef" +
|
||||
"GfP4Jz/ryV3fwy/Ssz70R+vM/Y/2zTrEwOTMrSYHRw+5mZe+fUbobMTlK7ilX4zcNH0xYy/nZ14CNtB92G5j5mUNXF8OYunL+QAerjz8aPjERTR8Pjp8hlt4aKztoRfRWCdnyHWdMZEF8DujH+Y+O/TwgfXpDjZa" +
|
||||
"9/hOZmh/5oCL8vRTy7m3sk/7SR+Oka9lrdxYYtakfoifeQlcmMH8wMmNg1XXB0ePdcR52axhrj5aHsDU5WJehK3sNjO8M9by4Ise/kRnAEeP/YmnsYbm3jpkD+hg9xy5CF4O+ljX9Uytrp0zkqe/0RtXSzQOasQ7" +
|
||||
"Sz15l3tIO+MSMFD9mCtDWFex1hI/8vARPHwd9/CTU3ldW5/1PfgiB1/OOl4E+sKdoeIWur0vYmmsgyV2e/eggcnzEMsT4fWxh3n4yY1X7OaaaVvbO8t9EtS/S9wRHq27tD3jEozmY7D6kWuuOYnwIw8fpx40fA5i" +
|
||||
"xviw5sExfPlFaH6YxcNekZiHn7U8/KLrJbIE/szoi43eA2sRS4T7eIg7ROseatVrH33X1E8czTrTtyVvB5+8PVvJ2etxF9+7BCzafbCRfrfAL6Eb3r72SoSPHl48tcST13xj5PrwkbHqX9X7X3rWg6/v4Rfp6eEX" +
|
||||
"XUdkBTgmXr2PX9bEEru9obFHEZ4Pe8Xv0MNe0Xp1/cQ6iz45HVeruKV/2iM+VvPwj9gof6T/Z+8SHFmcXBbi44qpwdMcKvNrHf7o4aVbK8dfefjIM3NND3xFD77Imsn1cxbW03dt/DTW1ZwBXw7Ww6YP1od9oiVW" +
|
||||
"jl+f2mfPdz7y5CPcUi5GHEuUXyMfv6nLxY+sB9nZl+CRMdgMhyFRTj83C3YPL5560YM2wi1113LNvQvgn/oVZ+sTm1mu3+0ZzQOXCK9PHnpi6dfDn37tM/KdhXg36ybfvqGcPHniVX3z71mXgE11H7bqbt5tWmNe" +
|
||||
"Irzz0Xjh1I6QmM9G78wYWI3+9eDr+6d9RfrsXQLWcV04VtdnbQ2uL0/00CXCuycPPvH0Pfi1Tl2scXzmEZ2t+uiY8fTVLwklx7yMyRNrXsaW+FmXYGUxhh19dHQ3kwgfPbxs6kaYa8F9NvrJXA8R7oGvWA9++vT2" +
|
||||
"EriOPn3VQC25Gljncf/G6iHTB2dPHnzy0q9cP/tVjbmId+jMK7i1uH1jeBr1L7eVS8Ag3Qfb0zOevNsUcYx1zAX3Hj4CNSAG1wcxtat3/+vaROSu60XIA185/T3womsm0l8fvmfOQJ68YncI0UZPHmQ5uMdrP+ZI" +
|
||||
"Tb/O1/lb6d17RhsZPTS5qC4e1S91K5fABR5FBuPja92gxs1NhPvw4jHyO424vSpaB6bRBwM99CIaBzt91siLwDp5+JPnDMm3ktuc8LScBx0/NX3mqBzNh5jcQ1599RGSb8zaxFzDWUYaOlZRLevNuRREjf6peOYl" +
|
||||
"YHA/9GjIUY6bpl6eCE+fD6FZo+YMI7SuYvaH18Pvwadv5Wrg6GE9Yph49e5/cxai+KOHfRNLrByfpx7o9OUVrR2hc2VcbYbbOLc9watRu2crOXs9nv63SBmi+6DqIoMk1wcxe5CD4ZsP8vCSOXz6IrpGnb49jSVS" +
|
||||
"iyXaL//UR/PAJzoLa6CDlattoVtcDmrkYc5y9T585zJHH2QOfXkifPR42I3ri+hy0VzQ9dWcI9E8NCxRrm7dJfHXT80xN3Pkmau2hGf+TTBbkAHrx9anLjeArt8h2ujhpWvZXw20Z/LaLw98x+nt4RfRZg/r5UzJ" +
|
||||
"iWkr89V58T1wifDVJw/6iNde3RwrGnvNPHxNPX35S3D1EjDY6KPlYHt5e3F6kYOxnjwRzsMHmdnevPahh3yGrOeFoHce/uTE8tncmw/HVma7Zn7Mhj+aj9mMycHK1TrMg2+804yN0Dn2kP3MjPqZ7cWt3c1bvQQ2" +
|
||||
"PIIszseuaI+94TIuB3n4ABw8fbVNutnooGWNyakldx0Pvz6968GvPr3J89EHtToja6fp50zE02emzlcHfciTd3jGoadvzpN8Cw1j5pGjoWEVr+pJv2dcAgasH3M2nhvaq8k8OchL9gLANTVyzDM2Q/NF+9PPnmrM" +
|
||||
"jJYInz1b+BaHY+TPjFk058KXz5BZiXeI5mOO/irWtbPOGJocxPSv3vh3NS87uEZqy/yMS1AXY6D6kTuNupXhM0cO8qLzkNKvGnlHnuyZa7COMZD9eRmOXID6XqrPmmn67oGYfITMZ0wOVt755o2Qvl2srqd/FLf2" +
|
||||
"d0aPap1Wc/CX8o5cAhrWj9YtnFqtST85NfjVWC91eSIfZXQZZvPSoz6uh25fkVge/OTE6rNJN00OYuTOzP2RI3dWNf2KzKsm7zA1uA+18oo1VtfR73A0N7pGnZYcrfrmPY1HLsFsMQbMD1t9alOrnHjW42Pkpenz" +
|
||||
"cTiEieSpwbHak3ofcuUi+XD7wtH0QXzXgXfPJt90eWLl+BpravLEyvHrw5xqlesnwo/69K91aq5dcSu5M3MM4GvJR1qXY+4SnnUJZosxJAdF03d4Y/rmdZg58kQ+igeUenvDySOGwfXlIPmJ9kOvHG30bKFbTA5i" +
|
||||
"1KwYc2hysHK1DplZXd5haiucnubZ/1HMPdIDE6/eva9+Ch69BAw3+oizmMN2OW44+6pZBxJPnY/ggRftIapbD9IjLwMcjcc1El0HDQ7uPVvKLUcOYtSuWO5V7pzUy1cwD6x8hkdirF/znWk0J7qWuWog+p7Ncmax" +
|
||||
"T32PXoJPxTsOQ/jBk1OmL6qBmHVX7/pLbjU1PoIHWw5i9qpIrRdAJMeZ7IMGB8kD67NJn7T04Rg1WnK1RPeFVrk+6GOevsjccjD9jqutYu2Za8mZrZoxUJOLVcevMXOewkcuAYOMPuIs5qDmiOiVm7uHfKw8/MyF" +
|
||||
"j+6Miazjga9orbPgJ8e3L7x7Nvmmy0GMfC25WiLrah1HU5evoIfbXH0RXS7uabWX/h7u7c/4COk/slnsruaRS3DXZCIwjB88eZaoO3jmZ96I87GoWbkM9gZZz4tgvbPgmyMf4ZZ6yTWu3yEaRu7MfBfm6HeIlrp+" +
|
||||
"h3mwjad2lNMja+w5w9wTeZh49T5+U0/+kXECe/UlYESGrx9draL5oDWrm+djUDO7DPYEeehNvlwdzAuSOhybacYvib9yO67WYe6742jqcpF+8oqjQ1v1o35dp/ruUT195000PtIy/hR/9BKwEQ9DHeBoLPPloMY6" +
|
||||
"6auP0MtAHQc5fXt58PVB8+XOoi+yrlxUE9G1ETc+w9x35fqJcB/6ykdYD7p5R3XrRlhn0Qcx6jCx8kswfjIv5AudxWruxX/0ErTNQmSQ/Pjpy0XL9EV0OEYv+UVY/KkXgD7OJU907dQqZ+nU0pcnVt75aGl1r+nL" +
|
||||
"EyvvfLTVZ3QJVuszj33pu0d8TLx6H7+pJ5/VfFQfZM9cAobjMDxj9uiQvvT3JSTv1rRHHtDK+RsAG12OzCcvfXnV9WdIDKPHEXPv1ujPkFjG9UV6yfdw5TLM+mWs42qJ8EeN/Ry2Zy7B3mIMlB89/Y6rJbIGPdCw" +
|
||||
"5Ffl+mtNah0fHX5y6T16ajx9eYepwTHWWDH3bG768g5Tg3e+usga8kewq0+t42qJM15j+KfYs5eAF7b6URk485O7GbVEYqyBhiW/KuNf+1AzeqhejWWufIYZg2usNzP3mjmpyWeYMXjnq+/FzGMeeWLV0++4Gpjm" +
|
||||
"HGjJM2fEj+bf+jx7CW6NBoTBZh/cuEgbeSI6fdCw5Ffl86+1de3UiflUnW7G7KFvbAUzB55m39Tg7nGmm7OCmQNf8Ud5I925a+9OVwOxrLkq/a95ffQJ9YxLwHCjD8poNV59x09dnkge66DNzJrMUXPO9NVAH2pn" +
|
||||
"3HiHqVWOr7muvjjaX+odV+swtcpX/L0cZicn82YaMcz8q/fxW/Xqf2Re2V685n/yz7gEnxouOgztIdjjxutGqa9aXd7aupa1oE/NVacnHNvDzKkcH7PH1Rv/dntLreNqM8xY5dVnOjSf9Ds+04yBmGvN+CXx1T9n" +
|
||||
"XQI2NPu4XTy1PW48Md8NaxObmbXkjDh93Edicur1k3cacS3jaivY7Ss1uUhPeWJyc/a0jI/4rJexxFVOHua6V+/+dy9+X1GU9sP8++/Dfdt+sWYXT22PG1/BLmdVY2Ryu3y3U2PWGO/8ldjs5ddY+nKRteSJyWtO" +
|
||||
"F1vVaq/OT23GiWGuffXuf/fi9xWb8s8/frpr+Ky/CdrFGpGhP09w3ahaxjuuBj5iWV/XrDF91jFXTG3GiWFZd1WO/Xb7TW2PG1/BM3LYXe2T2owTw6y/ei/8bT/OE38TMGrbs+yh5sz8jHVc7VWYe3KN1Crv/JGG" +
|
||||
"vmfdYaha+h2facbORvZlzxmvsc5Hq5a9a2zq178J8qPeCp+8BPRp+94WGMezLnntaUzMuFrFlZxZTVePhll39e79Pd14xdGHrvrIT73janvIXI/kZJ17s08X63LUErNH6kv8u1wChq0Hxw1UPf093sVn2iyWM3Z5" +
|
||||
"K/OaI2YftRnOPnaNzXxjImvKxU6bxbr81Ga8xvC1XFOt4kpOrbn577oELLjywUc5VZ/5GZOLdQ51MeOdlvHKV3xytOyvtoKzD15jMz9jHV/VmNlcMbXKV3xysOx3Ve5/V3Luq0J55yVg2ZUPP8qp+szP2Kt5t69c" +
|
||||
"M1730v4zf4+PDkDVZ37GXs3ZT67R+e655qknruRkfsvffQkYYnRA6oBd3oqWOcnr2hlb4bN6Z88+M81YxVp/5CN3uXtajad/lLOXUU2Nue/Mn2nGErvajC/zr7gEDFc/9mjgUV7Vq1/XqPH0kx+pq7nuofZTH+Vn" +
|
||||
"/CifHYQuVrWZf1aMPc165Z5rXsaSr+ZlzZB/1SVgoNlhyYFHeZ2+omVO8m6mvXhX4+y1Vr3DvdwjH32U2+lVO+Lv5bLPmjPSZjqxtK5nxg/zr7wEDLv38d3QLK+LrWg1p/rdfF1Ol+fce7HMe5bPDscoVvXqM1PV" +
|
||||
"9vyuZqShY7XnVb3/Xc27r5woX30JGG10sLqxZ7ld7B3ayh66Obr9PartHY5RvNPfobnPbi1jFY/k1tqp/x0uAQMeOSSz3FHsiH4k98jso77TD7QQXD0co7wj+pFcRh/l78Xqtmd9au5h/7tcAgY/ekhm+Y/ERjUj" +
|
||||
"/cjMsx6HP1pTsHpIZnmj2FGd8UY1e7Fma9NeXf5h7TtdAoZ/5LDs1czir4jlR5j1z7yz+Ozw5RqzvFfEWHvWN2dL/khN1i/x73YJHPro4VnJ38t5Nv7o7NadjasHaC/v2Tj72utR9340v9Yf8r/rJWATe4dytNGV" +
|
||||
"urNynplzNP+r9NWDtZJ3Vk6315XeXd3DWr0E7/7fE8wG92WsHNjss1JnDnWj/plj/y63yzM/savN+KN8df2u/5Ha1dzVvDrPo3W1z9P+d7oEboaX88gB8qXu1ZrnerP8mrtSY86o1vgr8ZG1j9Yczc/9PlObfU7h" +
|
||||
"3/ESsDFf0uyAjl6AtcRX6jPfnnt1XY21I9zrOap7ZK1RL/VHez5a9+y61r8Ev+slcLO+9LMO0Gof13UOcbXe/MRRz8w5mz+75rP17uesPvY7Fb/7JXCzvsRnDiG97AN/pFfW02Nkj/Qe9er01Tm62j3tzN5n9tqb" +
|
||||
"++H473IJ3KAv9YxDZi97g2f0pU/XG/272avmfFXfl7y/3+0S+BLyJZ91cOmdfV0LPHON7PsuPtrXmeu/Y40z5731+l0vwW0DG/Hlv/KgukauO+KvnCPXPDJT1p3Nv8scD+/rT7gEbr5+jHcdRtcX6xzqfwr+cfv7" +
|
||||
"ky5BPWT5sb7qQtSZflc/3+Xvuofh3H/yJchNdx/x52LkG/rg3bv6iP6B7G+5BN2n6z7233YxunfQvas/WvubL0H3YfcOxe92Sfb2072Dv077uQTHPvmzh+roJXp2vWO7+8n+eQM/b+DnDfy8gZ838PMGft7Azxv4" +
|
||||
"eQM/b+DnDfyFb+D/AdGPZ94O5ww1AAAAAElFTkSuQmCC";
|
||||
|
||||
byte[] bytes = Convert.FromBase64String(BASE64);
|
||||
|
||||
roundBlur20 = TextureUtilities.LoadImage(193, 193, bytes);
|
||||
|
||||
roundBlur20.hideFlags = HideFlags.HideAndDontSave;
|
||||
|
||||
CleanupUtility.DestroyObjectOnAssemblyReload(roundBlur20);
|
||||
}
|
||||
|
||||
return roundBlur20;
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D leftToRightFade;
|
||||
private static Texture2D topToBottomFade;
|
||||
private static Texture2D bottomToTopFade;
|
||||
private static Texture2D roundBlur6;
|
||||
private static Texture2D roundBlur20;
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
if (leftToRightFade != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(leftToRightFade);
|
||||
}
|
||||
|
||||
if (topToBottomFade != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(topToBottomFade);
|
||||
}
|
||||
|
||||
if (bottomToTopFade != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(bottomToTopFade);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78842ff15d254d9b8994383880b759f1
|
||||
timeCreated: 1704903394
|
||||
@@ -0,0 +1,55 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationMetadataRegistry.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine.Localization.Metadata;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public class OdinLocalizationMetadataRegistry
|
||||
{
|
||||
public static readonly List<Type> AssetEntryMetadataTypes = new List<Type>();
|
||||
|
||||
public static readonly List<Type> StringEntryMetadataTypes = new List<Type>();
|
||||
|
||||
public static readonly Dictionary<Type, bool> MetadataAllowsMultiple = new Dictionary<Type, bool>();
|
||||
|
||||
static OdinLocalizationMetadataRegistry()
|
||||
{
|
||||
TypeCache.TypeCollection metadataTypes = TypeCache.GetTypesDerivedFrom(typeof(IMetadata));
|
||||
|
||||
for (var i = 0; i < metadataTypes.Count; i++)
|
||||
{
|
||||
Type currentType = metadataTypes[i];
|
||||
|
||||
var attr = currentType.GetCustomAttribute<MetadataAttribute>();
|
||||
|
||||
if (attr is null)
|
||||
{
|
||||
MetadataAllowsMultiple[currentType] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
MetadataAllowsMultiple[currentType] = attr.AllowMultiple;
|
||||
|
||||
MetadataType currentAllowedTypes = attr.AllowedTypes;
|
||||
|
||||
if (currentAllowedTypes.HasFlag(MetadataType.StringTableEntry))
|
||||
{
|
||||
StringEntryMetadataTypes.Add(currentType);
|
||||
}
|
||||
|
||||
if (currentAllowedTypes.HasFlag(MetadataType.AssetTableEntry))
|
||||
{
|
||||
AssetEntryMetadataTypes.Add(currentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7deb6e0b5f6c4579ba2ead2af5620d3e
|
||||
timeCreated: 1706509329
|
||||
@@ -0,0 +1,43 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationReflectionValidator.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#if SIRENIX_INTERNAL
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Sirenix.OdinInspector.Editor.Validation;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
|
||||
[assembly: RegisterValidator(typeof(OdinLocalizationReflectionValidator))]
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public class OdinLocalizationReflectionValidator : GlobalValidator
|
||||
{
|
||||
public override IEnumerable RunValidation(ValidationResult result)
|
||||
{
|
||||
OdinLocalizationReflectionValues.EnsureInit();
|
||||
|
||||
FieldInfo[] fields = typeof(OdinLocalizationReflectionValues).GetFields(BindingFlags.Static | BindingFlags.Public);
|
||||
|
||||
for (var i = 0; i < fields.Length; i++)
|
||||
{
|
||||
if (fields[i].IsLiteral)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fields[i].GetValue(null) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.AddError($"[Odin Localization Module]: {fields[i].Name} was not found.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c12d37dc91fe4285bd661d45717bf34a
|
||||
timeCreated: 1704797628
|
||||
@@ -0,0 +1,174 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationReflectionValues.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Sirenix.Serialization;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine.Localization;
|
||||
using UnityEngine.Localization.Metadata;
|
||||
using UnityEngine.Localization.Tables;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationReflectionValues
|
||||
{
|
||||
public const string TABLE_ENTRY_DATA__METADATA__PATH = "m_Metadata";
|
||||
public const string METADATA_COLLECTION__ITEMS__PATH = "m_Items";
|
||||
public const string TABLE_ENTRY__DATA__PATH = "Data";
|
||||
|
||||
public static readonly bool HasAPIForCustomUndo = false;
|
||||
|
||||
public static readonly PropertyInfo TableEntry_Data_Property;
|
||||
public static readonly PropertyInfo AssetTableEntry_Data_Property;
|
||||
public static readonly PropertyInfo StringTableEntry_Data_Property;
|
||||
|
||||
public static readonly FieldInfo TableEntryData_m_Metadata_Field;
|
||||
public static readonly FieldInfo MetadataCollection_m_Items_Field;
|
||||
|
||||
public static readonly PropertyInfo LocalizationEditorSettings_Instance;
|
||||
public static readonly MethodInfo LocalizationEditorSettings_GetAddressableAssetSettings;
|
||||
public static readonly MethodInfo LocalizationEditorSettings_IsTableNameValid;
|
||||
|
||||
public static readonly MethodInfo RaiseTableEntryModified_Method;
|
||||
public static readonly MethodInfo RaiseTableEntryAdded_Method;
|
||||
public static readonly MethodInfo RaiseTableEntryRemoved_Method;
|
||||
public static readonly MethodInfo RaiseAssetTableEntryAdded_Method;
|
||||
public static readonly MethodInfo RaiseAssetTableEntryRemoved_Method;
|
||||
public static readonly MethodInfo AssetTableCollection_SetEntryAssetType_PrivateMethod;
|
||||
public static readonly MethodInfo AssetTableCollection_RemoveEntryAssetType_PrivateMethod;
|
||||
|
||||
public static readonly Type AddressHelper;
|
||||
public static readonly MethodInfo FormatAssetLabelMethod;
|
||||
public static readonly MethodInfo UpdateAssetGroupMethod;
|
||||
|
||||
private const BindingFlags INSTANCE_ALL = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
private const BindingFlags INSTANCE_NON_PUBLIC = BindingFlags.Instance | BindingFlags.NonPublic;
|
||||
private const BindingFlags STATIC_NON_PUBLIC = BindingFlags.Static | BindingFlags.NonPublic;
|
||||
|
||||
internal static Func<bool, AddressableAssetSettings> LocalizationEditorSettings_GetAddressableAssetSettingsFunc;
|
||||
|
||||
static OdinLocalizationReflectionValues()
|
||||
{
|
||||
TableEntry_Data_Property = typeof(TableEntry).GetProperty(TABLE_ENTRY__DATA__PATH, INSTANCE_ALL);
|
||||
AssetTableEntry_Data_Property = typeof(AssetTableEntry).BaseType.GetProperty(TABLE_ENTRY__DATA__PATH, INSTANCE_ALL);
|
||||
StringTableEntry_Data_Property = typeof(StringTableEntry).BaseType.GetProperty(TABLE_ENTRY__DATA__PATH, INSTANCE_ALL);
|
||||
|
||||
Type tableEntryDataType = TwoWaySerializationBinder.Default.BindToType("UnityEngine.Localization.Tables.TableEntryData, Unity.Localization");
|
||||
|
||||
TableEntryData_m_Metadata_Field = tableEntryDataType?.GetField(TABLE_ENTRY_DATA__METADATA__PATH, INSTANCE_ALL);
|
||||
MetadataCollection_m_Items_Field = typeof(MetadataCollection).GetField(METADATA_COLLECTION__ITEMS__PATH, INSTANCE_ALL);
|
||||
|
||||
LocalizationEditorSettings_Instance = typeof(LocalizationEditorSettings).GetProperty("Instance", STATIC_NON_PUBLIC);
|
||||
LocalizationEditorSettings_GetAddressableAssetSettings = typeof(LocalizationEditorSettings).GetMethod("GetAddressableAssetSettings",
|
||||
INSTANCE_NON_PUBLIC);
|
||||
LocalizationEditorSettings_IsTableNameValid = typeof(LocalizationEditorSettings).GetMethod("IsTableNameValid", INSTANCE_NON_PUBLIC);
|
||||
|
||||
|
||||
RaiseTableEntryModified_Method = LocalizationEditorSettings.EditorEvents.GetType().GetMethod("RaiseTableEntryModified", INSTANCE_ALL);
|
||||
RaiseTableEntryAdded_Method = LocalizationEditorSettings.EditorEvents.GetType().GetMethod("RaiseTableEntryAdded", INSTANCE_ALL);
|
||||
RaiseTableEntryRemoved_Method = LocalizationEditorSettings.EditorEvents.GetType().GetMethod("RaiseTableEntryRemoved", INSTANCE_ALL);
|
||||
RaiseAssetTableEntryAdded_Method = LocalizationEditorSettings.EditorEvents.GetType().GetMethod("RaiseAssetTableEntryAdded", INSTANCE_ALL);
|
||||
RaiseAssetTableEntryRemoved_Method = LocalizationEditorSettings.EditorEvents.GetType().GetMethod("RaiseAssetTableEntryRemoved", INSTANCE_ALL);
|
||||
AssetTableCollection_SetEntryAssetType_PrivateMethod = typeof(AssetTableCollection).GetMethod("SetEntryAssetType", INSTANCE_NON_PUBLIC);
|
||||
AssetTableCollection_RemoveEntryAssetType_PrivateMethod = typeof(AssetTableCollection).GetMethod("RemoveEntryAssetType", INSTANCE_NON_PUBLIC);
|
||||
|
||||
if (LocalizationEditorSettings_Instance != null && LocalizationEditorSettings_GetAddressableAssetSettings != null)
|
||||
{
|
||||
LocalizationEditorSettings_GetAddressableAssetSettingsFunc =
|
||||
(Func<bool, AddressableAssetSettings>) Delegate.CreateDelegate(typeof(Func<bool, AddressableAssetSettings>),
|
||||
LocalizationEditorSettings_Instance.GetValue(null),
|
||||
LocalizationEditorSettings_GetAddressableAssetSettings);
|
||||
}
|
||||
|
||||
AddressHelper = TwoWaySerializationBinder.Default.BindToType("UnityEngine.Localization.AddressHelper");
|
||||
|
||||
FormatAssetLabelMethod = AddressHelper?.GetMethod("FormatAssetLabel",
|
||||
BindingFlags.Static | BindingFlags.Public,
|
||||
null,
|
||||
new[] {typeof(LocaleIdentifier)},
|
||||
null);
|
||||
|
||||
UpdateAssetGroupMethod = typeof(AssetTableCollection).GetMethod("UpdateAssetGroup",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic,
|
||||
null,
|
||||
new[]
|
||||
{
|
||||
typeof(AddressableAssetSettings),
|
||||
typeof(AddressableAssetEntry),
|
||||
typeof(bool)
|
||||
},
|
||||
null);
|
||||
|
||||
HasAPIForCustomUndo = AddressHelper != null &&
|
||||
FormatAssetLabelMethod != null &&
|
||||
UpdateAssetGroupMethod != null &&
|
||||
LocalizationEditorSettings_GetAddressableAssetSettingsFunc != null;
|
||||
}
|
||||
|
||||
public static Action<SharedTableData.SharedTableEntry> Create_RaiseTableEntryModified_Method_Delegate(LocalizationEditorEvents events)
|
||||
{
|
||||
return (Action<SharedTableData.SharedTableEntry>) Delegate.CreateDelegate(typeof(Action<SharedTableData.SharedTableEntry>),
|
||||
events,
|
||||
RaiseTableEntryModified_Method);
|
||||
}
|
||||
|
||||
public static Action<LocalizationTableCollection, SharedTableData.SharedTableEntry> Create_RaiseTableEntryAdded_Method_Delegate(
|
||||
LocalizationEditorEvents events)
|
||||
{
|
||||
return (Action<LocalizationTableCollection, SharedTableData.SharedTableEntry>)
|
||||
Delegate.CreateDelegate(typeof(Action<LocalizationTableCollection, SharedTableData.SharedTableEntry>),
|
||||
events,
|
||||
RaiseTableEntryAdded_Method);
|
||||
}
|
||||
|
||||
public static Action<LocalizationTableCollection, SharedTableData.SharedTableEntry> Create_RaiseTableEntryRemoved_Method_Delegate(
|
||||
LocalizationEditorEvents events)
|
||||
{
|
||||
return (Action<LocalizationTableCollection, SharedTableData.SharedTableEntry>)
|
||||
Delegate.CreateDelegate(typeof(Action<LocalizationTableCollection, SharedTableData.SharedTableEntry>),
|
||||
events,
|
||||
RaiseTableEntryRemoved_Method);
|
||||
}
|
||||
|
||||
public static Action<AssetTableCollection, AssetTable, AssetTableEntry> Create_AssetTableEntryAdded_Method_Delegate(
|
||||
LocalizationEditorEvents events)
|
||||
{
|
||||
return (Action<AssetTableCollection, AssetTable, AssetTableEntry>)
|
||||
Delegate.CreateDelegate(typeof(Action<AssetTableCollection, AssetTable, AssetTableEntry>),
|
||||
events,
|
||||
RaiseAssetTableEntryAdded_Method);
|
||||
}
|
||||
|
||||
public static Action<AssetTableCollection, AssetTable, AssetTableEntry, string> Create_AssetTableEntryRemoved_Method_Delegate(
|
||||
LocalizationEditorEvents events)
|
||||
{
|
||||
return (Action<AssetTableCollection, AssetTable, AssetTableEntry, string>)
|
||||
Delegate.CreateDelegate(typeof(Action<AssetTableCollection, AssetTable, AssetTableEntry, string>),
|
||||
events,
|
||||
RaiseAssetTableEntryRemoved_Method);
|
||||
}
|
||||
|
||||
public static Action<TableEntryReference, Type, string> Create_AssetTableCollection_SetEntryAssetType_PrivateMethod_Delegate(AssetTableCollection collection)
|
||||
{
|
||||
return (Action<TableEntryReference, Type, string>) Delegate.CreateDelegate(typeof(Action<TableEntryReference, Type, string>),
|
||||
collection,
|
||||
AssetTableCollection_SetEntryAssetType_PrivateMethod);
|
||||
}
|
||||
|
||||
public static Action<TableEntryReference, string> Create_AssetTableCollection_RemoveEntryAssetType_PrivateMethod_Delegate(AssetTableCollection collection)
|
||||
{
|
||||
return (Action<TableEntryReference, string>) Delegate.CreateDelegate(typeof(Action<TableEntryReference, string>),
|
||||
collection,
|
||||
AssetTableCollection_RemoveEntryAssetType_PrivateMethod);
|
||||
}
|
||||
|
||||
#if SIRENIX_INTERNAL
|
||||
public static void EnsureInit() { }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b54903c48e344164a8ef89c56ba21f22
|
||||
timeCreated: 1704797678
|
||||
@@ -0,0 +1,223 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationSyntaxHighlighter.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Configs;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization.SmartFormat;
|
||||
using UnityEngine.Localization.SmartFormat.Core.Parsing;
|
||||
using UnityEngine.Localization.SmartFormat.Core.Settings;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor.Internal
|
||||
{
|
||||
public static class OdinLocalizationSyntaxHighlighter
|
||||
{
|
||||
private const string END_RICH_COLOR = "</color>";
|
||||
|
||||
private static readonly SmartFormatter Formatter;
|
||||
|
||||
private static readonly StringBuilder Buffer;
|
||||
|
||||
// TODO: if this works nicely, maybe implement a custom solution that doesn't rely on SmartFormatter
|
||||
|
||||
static OdinLocalizationSyntaxHighlighter()
|
||||
{
|
||||
Formatter = Smart.CreateDefaultSmartFormat();
|
||||
Formatter.Settings.ParseErrorAction = ErrorAction.MaintainTokens;
|
||||
Formatter.Settings.FormatErrorAction = ErrorAction.MaintainTokens;
|
||||
|
||||
Buffer = new StringBuilder();
|
||||
}
|
||||
|
||||
public static string HighlightAsRichText(string source)
|
||||
{
|
||||
Format format;
|
||||
|
||||
try
|
||||
{
|
||||
format = Formatter.Parser.ParseFormat(source, Formatter.GetNotEmptyFormatterExtensionNames());
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
Buffer.Clear();
|
||||
|
||||
int expectedSize = source.Length;
|
||||
AppendToBuffer(format, source, ref expectedSize);
|
||||
|
||||
// NOTE: we fallback to source in-case any obvious discrepancies are happening.
|
||||
return Buffer.Length != expectedSize ? source : Buffer.ToString();
|
||||
}
|
||||
|
||||
public static string GetErrorMessage(string source, out bool foundError, out Exception exception)
|
||||
{
|
||||
Formatter.Settings.ParseErrorAction = ErrorAction.OutputErrorInResult;
|
||||
Formatter.Settings.FormatErrorAction = ErrorAction.OutputErrorInResult;
|
||||
|
||||
Format format;
|
||||
|
||||
try
|
||||
{
|
||||
format = Formatter.Parser.ParseFormat(source, Formatter.GetNotEmptyFormatterExtensionNames());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
foundError = true;
|
||||
|
||||
exception = e;
|
||||
|
||||
Debug.LogException(e);
|
||||
|
||||
return $"Unity Formatter threw {ObjectNames.NicifyVariableName(e.GetType().GetNiceName())}: '{e.Message}'\nCheck the console for more information.";
|
||||
}
|
||||
|
||||
exception = null;
|
||||
|
||||
Buffer.Clear();
|
||||
|
||||
int expectedSize = source.Length;
|
||||
AppendToBuffer(format, source, ref expectedSize);
|
||||
|
||||
foundError = expectedSize != Buffer.Length;
|
||||
|
||||
Formatter.Settings.ParseErrorAction = ErrorAction.MaintainTokens;
|
||||
Formatter.Settings.FormatErrorAction = ErrorAction.MaintainTokens;
|
||||
|
||||
return Buffer.ToString();
|
||||
}
|
||||
|
||||
private static void AppendColorAsRichTag(Color color, ref int expectedSize)
|
||||
{
|
||||
var color32 = (Color32) color;
|
||||
|
||||
var richTag = $"<color=#{color32.r:X2}{color32.g:X2}{color32.b:X2}>";
|
||||
expectedSize += richTag.Length;
|
||||
|
||||
Buffer.Append(richTag);
|
||||
}
|
||||
|
||||
private static bool IsLastBufferEqual(string expected)
|
||||
{
|
||||
if (expected.Length > Buffer.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int bufferIndex = Buffer.Length - 1;
|
||||
|
||||
for (int i1 = expected.Length - 1; i1 >= 0; i1--, bufferIndex--)
|
||||
{
|
||||
if (Buffer[bufferIndex] != expected[i1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void AppendToBuffer(Format format, string source, ref int expectedSize)
|
||||
{
|
||||
for (var i = 0; i < format.Items.Count; i++)
|
||||
{
|
||||
if (Buffer.Length == source.Length)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FormatItem item = format.Items[i];
|
||||
|
||||
if (!(item is Placeholder placeholder))
|
||||
{
|
||||
Buffer.Append(item.RawText);
|
||||
continue;
|
||||
}
|
||||
|
||||
AppendColorAsRichTag(OdinLocalizationConfig.Instance.placeholderColor, ref expectedSize);
|
||||
|
||||
Buffer.Append('{');
|
||||
|
||||
for (var j = 0; j < placeholder.Selectors.Count; j++)
|
||||
{
|
||||
Selector selector = placeholder.Selectors[j];
|
||||
|
||||
AppendColorAsRichTag(OdinLocalizationConfig.Instance.selectorColor, ref expectedSize);
|
||||
|
||||
string op = selector.Operator;
|
||||
|
||||
if (!string.IsNullOrEmpty(op))
|
||||
{
|
||||
Buffer.Append(selector.Operator);
|
||||
}
|
||||
|
||||
Buffer.Append(selector.RawText);
|
||||
|
||||
Buffer.Append(END_RICH_COLOR);
|
||||
expectedSize += END_RICH_COLOR.Length;
|
||||
}
|
||||
|
||||
if (placeholder.Alignment != 0)
|
||||
{
|
||||
Buffer.Append(',');
|
||||
|
||||
Buffer.Append(placeholder.Alignment);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(placeholder.FormatterName))
|
||||
{
|
||||
Buffer.Append(':');
|
||||
|
||||
AppendColorAsRichTag(OdinLocalizationConfig.Instance.formatterColor, ref expectedSize);
|
||||
|
||||
Buffer.Append(placeholder.FormatterName);
|
||||
|
||||
if (!string.IsNullOrEmpty(placeholder.FormatterOptions))
|
||||
{
|
||||
Buffer.Append('(');
|
||||
Buffer.Append(placeholder.FormatterOptions);
|
||||
Buffer.Append(')');
|
||||
}
|
||||
|
||||
Buffer.Append(END_RICH_COLOR);
|
||||
expectedSize += END_RICH_COLOR.Length;
|
||||
}
|
||||
|
||||
if (placeholder.Format != null)
|
||||
{
|
||||
Format nextFormat = placeholder.Format;
|
||||
|
||||
bool showColon;
|
||||
|
||||
if (nextFormat.startIndex > 0)
|
||||
{
|
||||
showColon = nextFormat.baseString[nextFormat.startIndex - 1] == ':';
|
||||
}
|
||||
else
|
||||
{
|
||||
showColon = true;
|
||||
}
|
||||
|
||||
if (showColon)
|
||||
{
|
||||
Buffer.Append(':');
|
||||
}
|
||||
|
||||
AppendToBuffer(nextFormat, source, ref expectedSize);
|
||||
}
|
||||
|
||||
Buffer.Append('}');
|
||||
|
||||
Buffer.Append(END_RICH_COLOR);
|
||||
expectedSize += END_RICH_COLOR.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edfba57bc4284142a39f658cc44f70c6
|
||||
timeCreated: 1704797761
|
||||
@@ -0,0 +1,39 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="LocalizationSupport.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
using UnityEngine.Localization;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using System;
|
||||
using Sirenix.Utilities.Editor;
|
||||
|
||||
public class LocalizedReferenceResolver : OdinPropertyResolver<LocalizedReference>
|
||||
{
|
||||
public override int ChildNameToIndex(string name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override int ChildNameToIndex(ref StringSlice name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override InspectorPropertyInfo GetChildInfo(int childIndex)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected override int GetChildCount(LocalizedReference value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46db7b2a049564544ad19a2e480a1333
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationConstants.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Configs;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public static class OdinLocalizationConstants
|
||||
{
|
||||
public static int AssetPreviewRowHeight => OdinLocalizationConfig.Instance.assetRowHeight;
|
||||
public const int DEFAULT_COLUMN_WIDTH = 300;
|
||||
public const int MIN_COLUMN_WIDTH = 200;
|
||||
public const int COLUMN_HEIGHT = 38;
|
||||
public const int ROW_MENU_WIDTH = 28;
|
||||
public const int ROW_HEIGHT = 30;
|
||||
public const int EMPTY_ASSET_ROW_HEIGHT = ROW_HEIGHT; //96;
|
||||
public const int ASSET_ROW_HEIGHT = 104; //96;
|
||||
public const int ENTRY_PADDING = 4;
|
||||
public const int TOOLBAR_HEIGHT = 28;
|
||||
public const int DRAG_HANDLE_WIDTH = 27;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd2728f4c9e842db8d6b5e8c18cce611
|
||||
timeCreated: 1706411619
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "Sirenix.OdinInspector.Modules.UnityLocalization.Editor",
|
||||
"references": [
|
||||
"Unity.Localization",
|
||||
"Sirenix.Serialization",
|
||||
"Sirenix.OdinInspector.Attributes",
|
||||
"Sirenix.OdinInspector.Editor",
|
||||
"Sirenix.Utilities.Editor",
|
||||
"Unity.Localization.Editor",
|
||||
"Sirenix.Utilities",
|
||||
"Unity.Addressables.Editor"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [
|
||||
"Sirenix.Serialization.dll",
|
||||
"Sirenix.OdinInspector.Attributes.dll",
|
||||
"Sirenix.OdinInspector.Editor.dll",
|
||||
"Sirenix.Utilities.Editor.dll"
|
||||
],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3656feb4b010c5941972fb7b3b9eec3e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 835e118525d8475f939f4105af066578
|
||||
timeCreated: 1704796852
|
||||
@@ -0,0 +1,663 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="OdinLocalizationEditorWindow.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.OdinInspector.Editor.Internal;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Configs;
|
||||
using Sirenix.OdinInspector.Modules.Localization.Editor.Internal;
|
||||
using Sirenix.Serialization;
|
||||
using Sirenix.Utilities;
|
||||
using Sirenix.Utilities.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Localization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Localization;
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization.Editor
|
||||
{
|
||||
public class OdinLocalizationCreateTableMenu
|
||||
{
|
||||
[Serializable]
|
||||
public class LocaleItem
|
||||
{
|
||||
[HideInInspector]
|
||||
public Locale Locale;
|
||||
|
||||
[HideLabel]
|
||||
public bool Enabled;
|
||||
}
|
||||
|
||||
public enum TableCollectionType
|
||||
{
|
||||
StringTableCollection,
|
||||
AssetTableCollection
|
||||
}
|
||||
|
||||
private string FolderPath => string.IsNullOrEmpty(this.Folder) ? "Assets" : $"Assets/{this.Folder}";
|
||||
|
||||
[ValidateInput(nameof(ValidateName), "@this." + nameof(nameErrorMessage))]
|
||||
[VerticalGroup("Split/Left")]
|
||||
[PropertySpace(SpaceAfter = 2, SpaceBefore = 2)]
|
||||
public string Name;
|
||||
|
||||
[EnableIf("@this." + nameof(EnableFolder))]
|
||||
[InfoBox("The directory is not found, this will create a new directory on creation.", visibleIfMemberName: nameof(ShowFolderInfoBox))]
|
||||
[HorizontalGroup("Split")]
|
||||
[VerticalGroup("Split/Left")]
|
||||
[FolderPath(ParentFolder = "Assets")]
|
||||
public string Folder;
|
||||
|
||||
[VerticalGroup("Split/Left")]
|
||||
[PropertySpace(SpaceAfter = 2, SpaceBefore = 2)]
|
||||
[HideLabel]
|
||||
[EnumToggleButtons]
|
||||
public TableCollectionType Type;
|
||||
|
||||
[EnableIf(nameof(EnableCreateIf))]
|
||||
[VerticalGroup("Split/Left")]
|
||||
[PropertySpace(SpaceBefore = 4)]
|
||||
[Button(ButtonSizes.Large)]
|
||||
public void Create()
|
||||
{
|
||||
var localizationWindow = EditorWindow.focusedWindow as OdinLocalizationEditorWindow;
|
||||
|
||||
if (!this.HasAnyLocaleSelected())
|
||||
{
|
||||
if (localizationWindow)
|
||||
{
|
||||
localizationWindow.ShowToast(ToastPosition.BottomLeft,
|
||||
SdfIconType.ExclamationOctagonFill,
|
||||
"At least 1 Locale must be selected.",
|
||||
new Color(0.68f, 0.2f, 0.2f),
|
||||
5.0f);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(this.FolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(this.FolderPath);
|
||||
}
|
||||
|
||||
var collectionLocales = new List<Locale>(this.Locales.Count);
|
||||
|
||||
foreach (LocaleItem localeItem in this.Locales)
|
||||
{
|
||||
if (localeItem.Enabled)
|
||||
{
|
||||
collectionLocales.Add(localeItem.Locale);
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case TableCollectionType.StringTableCollection:
|
||||
LocalizationEditorSettings.CreateStringTableCollection(this.Name, this.FolderPath, collectionLocales);
|
||||
break;
|
||||
|
||||
case TableCollectionType.AssetTableCollection:
|
||||
LocalizationEditorSettings.CreateAssetTableCollection(this.Name, this.FolderPath, collectionLocales);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (localizationWindow)
|
||||
{
|
||||
string typeNiceName;
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case TableCollectionType.StringTableCollection:
|
||||
typeNiceName = "String Table Collection";
|
||||
break;
|
||||
|
||||
case TableCollectionType.AssetTableCollection:
|
||||
typeNiceName = "Asset Table Collection";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
localizationWindow.ShowToast(ToastPosition.BottomLeft,
|
||||
SdfIconType.Check2,
|
||||
$"{typeNiceName} '{this.Name}' created at: {this.FolderPath}.",
|
||||
new Color(0.29f, 0.57f, 0.42f),
|
||||
16.0f);
|
||||
}
|
||||
}
|
||||
|
||||
[HorizontalGroup("Split")]
|
||||
[VerticalGroup("Split/Right")]
|
||||
[InlineProperty]
|
||||
[ListDrawerSettings(ListElementLabelName = "@this.Locale.LocaleName",
|
||||
HideAddButton = true,
|
||||
HideRemoveButton = true,
|
||||
DefaultExpandedState = true,
|
||||
ShowFoldout = false,
|
||||
ShowItemCount = false,
|
||||
DraggableItems = false)]
|
||||
public List<LocaleItem> Locales = new List<LocaleItem>();
|
||||
|
||||
[HorizontalGroup("Split/Right/Split")]
|
||||
[Button]
|
||||
public void LocaleGenerator()
|
||||
{
|
||||
try
|
||||
{
|
||||
TwoWaySerializationBinder.Default.BindToType("UnityEditor.Localization.UI.LocaleGeneratorWindow, Unity.Localization.Editor")
|
||||
.GetMethod("ShowWindow", BindingFlags.Static | BindingFlags.Public)
|
||||
.Invoke(null, null);
|
||||
}
|
||||
catch (NullReferenceException nullReferenceException)
|
||||
{
|
||||
Debug.LogError($"[Odin]: Failed to find LocaleGeneratorWindow.ShowWindow.\n{nullReferenceException.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[HorizontalGroup("Split/Right/Split")]
|
||||
[Button]
|
||||
public void SelectNone()
|
||||
{
|
||||
for (var i = 0; i < this.Locales.Count; i++)
|
||||
{
|
||||
this.Locales[i].Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
[HorizontalGroup("Split/Right/Split")]
|
||||
[Button]
|
||||
public void SelectAll()
|
||||
{
|
||||
for (var i = 0; i < this.Locales.Count; i++)
|
||||
{
|
||||
this.Locales[i].Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
[HideInInspector]
|
||||
internal bool EnableFolder = true;
|
||||
|
||||
private string nameErrorMessage = string.Empty;
|
||||
|
||||
private bool ValidateName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
this.nameErrorMessage = $"{nameof(this.Name)} can't be empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
Type collectionType;
|
||||
|
||||
switch (this.Type)
|
||||
{
|
||||
case TableCollectionType.StringTableCollection:
|
||||
collectionType = typeof(StringTableCollection);
|
||||
break;
|
||||
|
||||
case TableCollectionType.AssetTableCollection:
|
||||
collectionType = typeof(AssetTableCollection);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
bool isTableNameValid = OdinLocalizationEditorSettings.IsTableNameValid(collectionType, name, out string localizationErrorMsg);
|
||||
|
||||
if (isTableNameValid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
this.nameErrorMessage = localizationErrorMsg;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool ShowFolderInfoBox()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.Folder))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Directory.Exists(this.FolderPath);
|
||||
}
|
||||
|
||||
private bool EnableCreateIf() => this.Locales.Count > 0 && this.ValidateName(this.Name);
|
||||
|
||||
private bool HasAnyLocaleSelected()
|
||||
{
|
||||
for (var i = 0; i < this.Locales.Count; i++)
|
||||
{
|
||||
if (this.Locales[i].Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class OdinLocalizationEditorWindow : OdinMenuEditorWindow, IDisposable
|
||||
{
|
||||
public enum RightMenuTopTabs
|
||||
{
|
||||
[LabelText(SdfIconType.Braces)]
|
||||
Metadata,
|
||||
|
||||
[LabelText(SdfIconType.GearFill)]
|
||||
Settings
|
||||
}
|
||||
|
||||
public enum RightMenuBottomTabs
|
||||
{
|
||||
[LabelText(SdfIconType.FlagFill)]
|
||||
Locale,
|
||||
|
||||
#if false
|
||||
[LabelText(SdfIconType.BorderWidth)]
|
||||
Template,
|
||||
#endif
|
||||
|
||||
[LabelText(SdfIconType.GearFill)]
|
||||
Settings
|
||||
}
|
||||
|
||||
public class WindowState : IDisposable
|
||||
{
|
||||
public static string EditorPrefsKey = "OdinLocalizationEditorWindow_EditorPrefs";
|
||||
|
||||
public RightMenuTopTabs CurrentTopTab;
|
||||
public RightMenuBottomTabs CurrentBottomTab;
|
||||
public PropertyTree MetadataTree = null;
|
||||
public bool ShowSharedMetadata = true;
|
||||
|
||||
public float LeftMenuWidth;
|
||||
public float RightMenuWidth;
|
||||
public float RightMenuTopPanelHeight;
|
||||
public float LastOpenRightMenuWidth;
|
||||
|
||||
public void Save()
|
||||
{
|
||||
EditorPrefs.SetFloat($"{EditorPrefsKey}_LeftMenuWidth", this.LeftMenuWidth);
|
||||
EditorPrefs.SetFloat($"{EditorPrefsKey}_RightMenuWidth", this.RightMenuWidth);
|
||||
EditorPrefs.SetFloat($"{EditorPrefsKey}_RightMenuTopHeight", this.RightMenuTopPanelHeight);
|
||||
EditorPrefs.SetFloat($"{EditorPrefsKey}_LastOpenRightMenuWidth", this.LastOpenRightMenuWidth);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
this.LeftMenuWidth = EditorPrefs.GetFloat($"{EditorPrefsKey}_LeftMenuWidth", 300);
|
||||
this.RightMenuWidth = EditorPrefs.GetFloat($"{EditorPrefsKey}_RightMenuWidth", 300);
|
||||
this.RightMenuTopPanelHeight = EditorPrefs.GetFloat($"{EditorPrefsKey}_RightMenuTopHeight");
|
||||
this.LastOpenRightMenuWidth = EditorPrefs.GetFloat($"{EditorPrefsKey}_LastOpenRightMenuWidth");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.MetadataTree?.Dispose();
|
||||
this.MetadataTree = null;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Odin/Localization Editor", priority = 10_100)]
|
||||
public static void OpenFromMenu()
|
||||
{
|
||||
var wnd = GetWindow<OdinLocalizationEditorWindow>();
|
||||
wnd.MenuWidth = 300.0f;
|
||||
}
|
||||
|
||||
public WindowState State;
|
||||
|
||||
private object lastSelection;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
this.State = new WindowState();
|
||||
this.State.Load();
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
this.DisposeActiveCollection();
|
||||
this.State.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
this.State.Save();
|
||||
|
||||
this.DisposeActiveCollection();
|
||||
this.State.Dispose();
|
||||
}
|
||||
|
||||
protected override void OnImGUI()
|
||||
{
|
||||
if (LocalizationEditorSettings.ActiveLocalizationSettings == null)
|
||||
{
|
||||
Rect popupPosition = this.position.SetPosition(Vector2.zero).AlignCenter(360, 160);
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
//OdinLocalizationGUI.DrawRoundGlowRect(popupPosition.Expand(54), FancyColor.CreateHex(0x323232));
|
||||
OdinLocalizationGUI.DrawRoundBlur6(popupPosition, new Color(0, 0, 0, 0.025f));
|
||||
SirenixEditorGUI.DrawRoundRect(popupPosition, FancyColor.CreateHex(0x383838), 5.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
OdinLocalizationGUI.DrawRoundBlur6(popupPosition, new Color(0, 0, 0, 0.02f));
|
||||
SirenixEditorGUI.DrawRoundRect(popupPosition, new FancyColor(0.84f), 5.0f); //, new Color(0, 0, 0, 0.2f), 1);
|
||||
|
||||
SirenixEditorGUI.DrawRoundRect(popupPosition.AlignBottom(32 + 12 + 8 + 6), new Color(1, 1, 1, 0.2f), 0.0f, 0.0f, 5.0f, 5.0f);
|
||||
}
|
||||
|
||||
popupPosition = popupPosition.Padding(12);
|
||||
|
||||
Rect buttonsArea = popupPosition.TakeFromBottom(32);
|
||||
|
||||
popupPosition.height -= 16;
|
||||
|
||||
GUIStyle labelStyle = EditorGUIUtility.isProSkin ? SirenixGUIStyles.WhiteLabelCentered : SirenixGUIStyles.BlackLabelCentered;
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
GUI.Label(popupPosition, "No Localization Settings found in project.", labelStyle);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUIHelper.PushColor(new Color(1, 1, 1, 0.75f));
|
||||
GUI.Label(popupPosition, "No Localization Settings found in project.", SirenixGUIStyles.BlackLabelCentered);
|
||||
}
|
||||
|
||||
if (OdinLocalizationGUI.OverlaidButton(buttonsArea.AlignCenter(120), "Create", labelStyle: labelStyle, invert: true))
|
||||
{
|
||||
if (OdinLocalizationEditorSettings.CreateDefaultLocalizationSettingsAsset())
|
||||
{
|
||||
this.ShowToast(ToastPosition.BottomLeft,
|
||||
SdfIconType.GearWide,
|
||||
"Default Localization Settings created.",
|
||||
new Color(0.13f, 0.26f, 0.39f),
|
||||
8.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!EditorGUIUtility.isProSkin)
|
||||
{
|
||||
GUIHelper.PopColor();
|
||||
}
|
||||
|
||||
this.Repaint();
|
||||
return;
|
||||
}
|
||||
|
||||
base.OnImGUI();
|
||||
}
|
||||
|
||||
protected override OdinMenuTree BuildMenuTree()
|
||||
{
|
||||
var tree = new OdinMenuTree
|
||||
{
|
||||
Config =
|
||||
{
|
||||
AutoHandleKeyboardNavigation = false,
|
||||
DrawSearchToolbar = true
|
||||
},
|
||||
DefaultMenuStyle =
|
||||
{
|
||||
Height = 28,
|
||||
AlignTriangleLeft = true,
|
||||
TrianglePadding = 0.0f
|
||||
}
|
||||
};
|
||||
|
||||
this.MenuBackgroundColor = OdinLocalizationGUI.MenuBackground;
|
||||
|
||||
if (LocalizationEditorSettings.ActiveLocalizationSettings == null)
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
var createMenu = new OdinLocalizationCreateTableMenu();
|
||||
|
||||
tree.Add("Create Table", createMenu, SdfIconType.Plus);
|
||||
tree.Add("User Config", OdinLocalizationConfig.Instance, SdfIconType.GearFill);
|
||||
|
||||
#if true
|
||||
tree.Selection.SelectionChanged += type =>
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case SelectionChangedType.ItemAdded:
|
||||
if (this.lastSelection != null)
|
||||
{
|
||||
switch (this.lastSelection)
|
||||
{
|
||||
case OdinAssetTableCollectionEditor assetCollection:
|
||||
{
|
||||
assetCollection.DetachEvents();
|
||||
break;
|
||||
}
|
||||
|
||||
case OdinStringTableCollectionEditor stringCollection:
|
||||
{
|
||||
stringCollection.DetachEvents();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.State.MetadataTree?.Dispose();
|
||||
this.State.MetadataTree = null;
|
||||
}
|
||||
|
||||
switch (tree.Selection.SelectedValue)
|
||||
{
|
||||
case OdinAssetTableCollectionEditor assetCollection:
|
||||
{
|
||||
assetCollection.OnSelectInWindow();
|
||||
|
||||
if (assetCollection.SelectionType == OdinTableSelectionType.TableEntry && this.State.CurrentTopTab == RightMenuTopTabs.Metadata)
|
||||
{
|
||||
assetCollection.UpdateMetadataViewForEntry(assetCollection.CurrentSelectedEntry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OdinStringTableCollectionEditor stringCollection:
|
||||
{
|
||||
stringCollection.OnSelectInWindow();
|
||||
|
||||
if (stringCollection.SelectionType == OdinTableSelectionType.TableEntry && this.State.CurrentTopTab == RightMenuTopTabs.Metadata)
|
||||
{
|
||||
stringCollection.UpdateMetadataViewForEntry(stringCollection.CurrentSelectedEntry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case OdinLocalizationCreateTableMenu createTableMenu:
|
||||
createTableMenu.Locales.Clear();
|
||||
|
||||
foreach (Locale locale in LocalizationEditorSettings.GetLocales())
|
||||
{
|
||||
createTableMenu.Locales.Add(new OdinLocalizationCreateTableMenu.LocaleItem {Locale = locale, Enabled = true});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
this.lastSelection = this.MenuTree.Selection.SelectedValue;
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
string[] collectionGUIDs = AssetDatabase.FindAssets($"t:{nameof(LocalizationTableCollection)}");
|
||||
|
||||
for (var i = 0; i < collectionGUIDs.Length; i++)
|
||||
{
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(collectionGUIDs[i]);
|
||||
|
||||
var collection = AssetDatabase.LoadAssetAtPath<LocalizationTableCollection>(assetPath);
|
||||
|
||||
AssetTableCollection assetTableCollection = LocalizationEditorSettings.GetAssetTableCollection(collection.TableCollectionNameReference);
|
||||
|
||||
if (assetTableCollection != null)
|
||||
{
|
||||
var guiCollection = new OdinAssetTableCollectionEditor(assetTableCollection, this, this.State);
|
||||
|
||||
assetPath = assetPath.Replace(".asset", string.Empty);
|
||||
|
||||
if (assetPath.StartsWith("Assets/"))
|
||||
{
|
||||
assetPath = assetPath.Remove(0, "Assets/".Length);
|
||||
}
|
||||
|
||||
tree.Add(assetPath, guiCollection, SdfIconType.Table);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
StringTableCollection stringTableCollection = LocalizationEditorSettings.GetStringTableCollection(collection.TableCollectionNameReference);
|
||||
|
||||
if (stringTableCollection != null)
|
||||
{
|
||||
var guiCollection = new OdinStringTableCollectionEditor(stringTableCollection, this, this.State);
|
||||
|
||||
assetPath = assetPath.Replace(".asset", string.Empty);
|
||||
|
||||
if (assetPath.StartsWith("Assets/"))
|
||||
{
|
||||
assetPath = assetPath.Remove(0, "Assets/".Length);
|
||||
}
|
||||
|
||||
tree.Add(assetPath, guiCollection, SdfIconType.LayoutTextWindow);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (OdinMenuItem treeMenuItem in tree.EnumerateTree())
|
||||
{
|
||||
if (treeMenuItem.Value != null)
|
||||
{
|
||||
if (treeMenuItem.Value is OdinAssetTableCollectionEditor assetEditor)
|
||||
{
|
||||
treeMenuItem.Name = assetEditor.Collection.SharedData.TableCollectionName;
|
||||
|
||||
assetEditor.MenuItem = treeMenuItem;
|
||||
|
||||
treeMenuItem.OnDrawItem += item =>
|
||||
{
|
||||
if (Event.current.OnMouseDown(item.Rect, 0, false))
|
||||
{
|
||||
if (Event.current.clickCount > 1)
|
||||
{
|
||||
EditorGUIUtility.PingObject(assetEditor.Collection);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (treeMenuItem.Value is OdinStringTableCollectionEditor stringEditor)
|
||||
{
|
||||
treeMenuItem.Name = stringEditor.Collection.SharedData.TableCollectionName;
|
||||
|
||||
stringEditor.MenuItem = treeMenuItem;
|
||||
|
||||
treeMenuItem.OnDrawItem += item =>
|
||||
{
|
||||
if (Event.current.OnMouseDown(item.Rect, 0, false))
|
||||
{
|
||||
if (Event.current.clickCount > 1)
|
||||
{
|
||||
EditorGUIUtility.PingObject(stringEditor.Collection);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
treeMenuItem.Value = createMenu;
|
||||
|
||||
treeMenuItem.SdfIcon = SdfIconType.FolderFill;
|
||||
|
||||
treeMenuItem.OnDrawItem += item =>
|
||||
{
|
||||
Rect addTableRect = item.Rect.AlignRight(20).SubX(14);
|
||||
|
||||
bool isMouseOver = Event.current.IsMouseOver(addTableRect);
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
SdfIcons.DrawIcon(addTableRect.AlignCenter(16, 16),
|
||||
SdfIconType.Plus,
|
||||
isMouseOver ? new Color(1, 1, 1, 0.8f) : new Color(1, 1, 1, 0.4f));
|
||||
}
|
||||
else
|
||||
{
|
||||
SdfIcons.DrawIcon(addTableRect.AlignCenter(16, 16),
|
||||
SdfIconType.Plus,
|
||||
isMouseOver ? new Color(0, 0, 0, 0.8f) : new Color(0, 0, 0, 0.4f));
|
||||
}
|
||||
|
||||
if (Event.current.OnMouseDown(item.Rect, 0, false))
|
||||
{
|
||||
createMenu.Folder = treeMenuItem.GetFullPath();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.DisposeActiveCollection();
|
||||
this.State.Dispose();
|
||||
}
|
||||
|
||||
private void DisposeActiveCollection()
|
||||
{
|
||||
if (this.MenuTree == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.MenuTree.Selection.SelectedValue)
|
||||
{
|
||||
case OdinAssetTableCollectionEditor assetCollection:
|
||||
assetCollection.DetachEvents();
|
||||
break;
|
||||
|
||||
case OdinStringTableCollectionEditor stringCollection:
|
||||
stringCollection.DetachEvents();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7cd6c96ce4b4c2c98fae9f89eedc690
|
||||
timeCreated: 1704796865
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2477452e56429547b05666cbaaf3502
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="LocalizedStringFormatter.cs" company="Sirenix ApS">
|
||||
// Copyright (c) Sirenix ApS. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
using Sirenix.Serialization;
|
||||
using System.Reflection;
|
||||
using UnityEngine.Localization;
|
||||
using System;
|
||||
|
||||
#if !ODIN_INSPECTOR_EDITOR_ONLY
|
||||
[assembly: RegisterFormatter(typeof(Sirenix.OdinInspector.Modules.Localization.LocalizedStringFormatter))]
|
||||
#endif
|
||||
|
||||
namespace Sirenix.OdinInspector.Modules.Localization
|
||||
{
|
||||
#if !ODIN_INSPECTOR_EDITOR_ONLY
|
||||
public class LocalizedStringFormatter : ReflectionOrEmittedBaseFormatter<LocalizedString>
|
||||
{
|
||||
private static readonly FieldInfo m_LocalVariables_Field;
|
||||
|
||||
static LocalizedStringFormatter()
|
||||
{
|
||||
m_LocalVariables_Field = typeof(LocalizedString).GetField("m_LocalVariables", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (m_LocalVariables_Field == null)
|
||||
{
|
||||
DefaultLoggers.DefaultLogger.LogError("Could not find field 'UnityEngine.LocalizedString.m_LocalVariables'" +
|
||||
" - the internals of the Localization package have changed, and deserialization of Odin-serialized" +
|
||||
" LocalizedString instances may be broken in some cases.");
|
||||
}
|
||||
}
|
||||
|
||||
protected override LocalizedString GetUninitializedObject()
|
||||
{
|
||||
return new LocalizedString();
|
||||
}
|
||||
|
||||
protected override void DeserializeImplementation(ref LocalizedString value, IDataReader reader)
|
||||
{
|
||||
base.DeserializeImplementation(ref value, reader);
|
||||
|
||||
if (m_LocalVariables_Field != null && value != null)
|
||||
{
|
||||
var localVariablesList = m_LocalVariables_Field.GetValue(value);
|
||||
|
||||
// This list is not allowed to be null!
|
||||
if (localVariablesList == null)
|
||||
{
|
||||
localVariablesList = Activator.CreateInstance(m_LocalVariables_Field.FieldType);
|
||||
m_LocalVariables_Field.SetValue(value, localVariablesList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93ff93294e9339b40b68190c779d0009
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Sirenix.OdinInspector.Modules.UnityLocalization",
|
||||
"references": [ "Unity.Localization", "Sirenix.Serialization", "Sirenix.Serialization.Config" ],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"autoReferenced": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [ "Sirenix.Serialization.dll", "Sirenix.Serialization.Config.dll" ],
|
||||
"defineConstraints": [ "!ODIN_INSPECTOR_EDITOR_ONLY" ]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09320d9ddd505f84d9a6e5203cf75192
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
ManifestVersion: 1
|
||||
ModuleID: Unity.Localization
|
||||
ModuleVersion: 2.0.0.5
|
||||
ModuleFiles:
|
||||
Editor.meta
|
||||
Runtime.meta
|
||||
Editor/Configs.meta
|
||||
Editor/GUI.meta
|
||||
Editor/Internal.meta
|
||||
Editor/LocalizationSupport.cs
|
||||
Editor/LocalizationSupport.cs.meta
|
||||
Editor/OdinLocalizationConstants.cs
|
||||
Editor/OdinLocalizationConstants.cs.meta
|
||||
Editor/Sirenix.OdinInspector.Modules.UnityLocalization.Editor.asmdef
|
||||
Editor/Sirenix.OdinInspector.Modules.UnityLocalization.Editor.asmdef.meta
|
||||
Editor/Windows.meta
|
||||
Editor/Configs/OdinLocalizationConfig.asset
|
||||
Editor/Configs/OdinLocalizationConfig.asset.meta
|
||||
Editor/Configs/OdinLocalizationConfig.cs
|
||||
Editor/Configs/OdinLocalizationConfig.cs.meta
|
||||
Editor/GUI/LocalizationMetadata.cs
|
||||
Editor/GUI/LocalizationMetadata.cs.meta
|
||||
Editor/GUI/OdinAssetTableCollectionEditor.cs
|
||||
Editor/GUI/OdinAssetTableCollectionEditor.cs.meta
|
||||
Editor/GUI/OdinGUITable.cs
|
||||
Editor/GUI/OdinGUITable.cs.meta
|
||||
Editor/GUI/OdinGUITableCollection.cs
|
||||
Editor/GUI/OdinGUITableCollection.cs.meta
|
||||
Editor/GUI/OdinSharedEntryCollection.cs
|
||||
Editor/GUI/OdinSharedEntryCollection.cs.meta
|
||||
Editor/GUI/OdinStringTableCollectionEditor.cs
|
||||
Editor/GUI/OdinStringTableCollectionEditor.cs.meta
|
||||
Editor/GUI/OdinTableCollectionEditor.cs
|
||||
Editor/GUI/OdinTableCollectionEditor.cs.meta
|
||||
Editor/GUI/OdinTemplateMetadata.cs
|
||||
Editor/GUI/OdinTemplateMetadata.cs.meta
|
||||
Editor/GUI/Toggle.cs
|
||||
Editor/GUI/Toggle.cs.meta
|
||||
Editor/Internal/OdinLocalizationAssetCache.cs
|
||||
Editor/Internal/OdinLocalizationAssetCache.cs.meta
|
||||
Editor/Internal/OdinLocalizationEditorSettings.cs
|
||||
Editor/Internal/OdinLocalizationEditorSettings.cs.meta
|
||||
Editor/Internal/OdinLocalizationEvents.cs
|
||||
Editor/Internal/OdinLocalizationEvents.cs.meta
|
||||
Editor/Internal/OdinLocalizationGUI.cs
|
||||
Editor/Internal/OdinLocalizationGUI.cs.meta
|
||||
Editor/Internal/OdinLocalizationGUITextures.cs
|
||||
Editor/Internal/OdinLocalizationGUITextures.cs.meta
|
||||
Editor/Internal/OdinLocalizationMetadataRegistry.cs
|
||||
Editor/Internal/OdinLocalizationMetadataRegistry.cs.meta
|
||||
Editor/Internal/OdinLocalizationReflectionValidator.cs
|
||||
Editor/Internal/OdinLocalizationReflectionValidator.cs.meta
|
||||
Editor/Internal/OdinLocalizationReflectionValues.cs
|
||||
Editor/Internal/OdinLocalizationReflectionValues.cs.meta
|
||||
Editor/Internal/OdinLocalizationSyntaxHighlighter.cs
|
||||
Editor/Internal/OdinLocalizationSyntaxHighlighter.cs.meta
|
||||
Editor/Windows/OdinLocalizationEditorWindow.cs
|
||||
Editor/Windows/OdinLocalizationEditorWindow.cs.meta
|
||||
Runtime/LocalizedStringFormatter.cs
|
||||
Runtime/LocalizedStringFormatter.cs.meta
|
||||
Runtime/Sirenix.OdinInspector.Modules.UnityLocalization.asmdef
|
||||
Runtime/Sirenix.OdinInspector.Modules.UnityLocalization.asmdef.meta
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6dd57bba224954bb890cd5ccb1aa3747
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user