Streamingle_URP/Assets/Scripts/Editor/Utilities/MotionCaptureFileRenamer.cs

467 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System;
/// <summary>
/// 모션 캡쳐 파일 네이밍 편의성 툴
/// - 선택한 파일들에 일괄적으로 접미사/접두사 추가
/// - 번호 매기기, 날짜 스탬프 등 다양한 네이밍 패턴 지원
/// </summary>
public class MotionCaptureFileRenamer : EditorWindow
{
#region Nested Classes
[Serializable]
public class NamingPreset
{
public string presetName = "New Preset";
public NamingMode mode = NamingMode.Suffix;
public string customText = "";
public int startNumber = 1;
public int numberPadding = 3;
public string separator = "_";
}
public enum NamingMode
{
Suffix, // 파일명 뒤에 추가
Prefix, // 파일명 앞에 추가
Replace, // 전체 이름 변경
Sequential // 순차 번호
}
#endregion
#region Fields
private List<UnityEngine.Object> selectedFiles = new List<UnityEngine.Object>();
private Vector2 scrollPosition;
private Vector2 fileListScrollPosition;
private Vector2 previewScrollPosition;
// Naming settings
private NamingMode namingMode = NamingMode.Suffix;
private string customText = "_ok";
private int startNumber = 1;
private int numberPadding = 3;
private string separator = "_";
// Presets
private List<NamingPreset> presets = new List<NamingPreset>();
private int selectedPresetIndex = -1;
private bool showPresetSection = false;
private string newPresetName = "My Preset";
// UI Style
private GUIStyle headerStyle;
private GUIStyle boxStyle;
private Color successColor = new Color(0.5f, 1f, 0.5f, 0.3f);
private Color warningColor = new Color(1f, 1f, 0.5f, 0.3f);
private Color errorColor = new Color(1f, 0.5f, 0.5f, 0.3f);
#endregion
#region Window Initialization
[MenuItem("Tools/Motion Capture Tools/File Renamer")]
public static void ShowWindow()
{
var window = GetWindow<MotionCaptureFileRenamer>("MoCap File Renamer");
window.minSize = new Vector2(450, 500);
}
private void OnEnable()
{
LoadPresets();
RefreshSelectedFiles();
Selection.selectionChanged += OnSelectionChanged;
}
private void OnDisable()
{
SavePresets();
Selection.selectionChanged -= OnSelectionChanged;
}
private void OnSelectionChanged()
{
RefreshSelectedFiles();
Repaint();
}
private void InitializeStyles()
{
if (headerStyle == null)
{
headerStyle = new GUIStyle(EditorStyles.boldLabel)
{
fontSize = 14,
alignment = TextAnchor.MiddleLeft
};
}
if (boxStyle == null)
{
boxStyle = new GUIStyle(EditorStyles.helpBox)
{
padding = new RectOffset(10, 10, 10, 10)
};
}
}
#endregion
#region GUI
private void OnGUI()
{
InitializeStyles();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
DrawHeader();
DrawFileSelectionSection();
DrawNamingOptionsSection();
DrawPresetsSection();
DrawActionButtons();
EditorGUILayout.EndScrollView();
}
private void DrawHeader()
{
EditorGUILayout.Space(5);
EditorGUILayout.LabelField("🎬 MoCap File Renamer", headerStyle);
EditorGUILayout.Space(5);
}
private void DrawFileSelectionSection()
{
EditorGUILayout.BeginVertical(boxStyle);
// 선택된 파일 수 표시
GUIStyle countStyle = new GUIStyle(EditorStyles.boldLabel);
countStyle.fontSize = 13;
if (selectedFiles.Count > 0)
{
countStyle.normal.textColor = new Color(0.3f, 0.8f, 0.3f);
EditorGUILayout.LabelField($"📁 {selectedFiles.Count} files selected", countStyle);
}
else
{
countStyle.normal.textColor = Color.gray;
EditorGUILayout.LabelField($"📁 No files selected", countStyle);
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
}
private void DrawNamingOptionsSection()
{
EditorGUILayout.BeginVertical(boxStyle);
EditorGUILayout.LabelField("⚙️ Naming Options", EditorStyles.boldLabel);
EditorGUILayout.Space(5);
// Naming mode
namingMode = (NamingMode)EditorGUILayout.EnumPopup("Mode", namingMode);
switch (namingMode)
{
case NamingMode.Suffix:
customText = EditorGUILayout.TextField("Suffix", customText);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("_ok")) customText = "_ok";
if (GUILayout.Button("_final")) customText = "_final";
if (GUILayout.Button("_test")) customText = "_test";
EditorGUILayout.EndHorizontal();
break;
case NamingMode.Prefix:
customText = EditorGUILayout.TextField("Prefix", customText);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Take001")) customText = "Take001";
if (GUILayout.Button("MoCap")) customText = "MoCap";
if (GUILayout.Button("Test")) customText = "Test";
EditorGUILayout.EndHorizontal();
break;
case NamingMode.Replace:
customText = EditorGUILayout.TextField("New Name", customText);
startNumber = EditorGUILayout.IntField("Start Number", startNumber);
numberPadding = EditorGUILayout.IntSlider("Padding", numberPadding, 1, 5);
break;
case NamingMode.Sequential:
customText = EditorGUILayout.TextField("Base Name", customText);
startNumber = EditorGUILayout.IntField("Start Number", startNumber);
numberPadding = EditorGUILayout.IntSlider("Padding", numberPadding, 1, 5);
EditorGUILayout.LabelField($"Ex: {customText}{startNumber.ToString().PadLeft(numberPadding, '0')}", EditorStyles.miniLabel);
break;
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space(5);
}
private void DrawPresetsSection()
{
showPresetSection = EditorGUILayout.Foldout(showPresetSection, "💾 Presets", true, EditorStyles.foldoutHeader);
if (showPresetSection)
{
EditorGUILayout.BeginVertical(boxStyle);
if (presets.Count > 0)
{
for (int i = 0; i < presets.Count; i++)
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(presets[i].presetName, GUILayout.Height(22)))
{
LoadPreset(i);
}
if (GUILayout.Button("×", GUILayout.Width(25), GUILayout.Height(22)))
{
presets.RemoveAt(i);
SavePresets();
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.Space(3);
}
EditorGUILayout.BeginHorizontal();
newPresetName = EditorGUILayout.TextField(newPresetName);
if (GUILayout.Button("Save", GUILayout.Width(60)))
{
SaveCurrentAsPreset();
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
EditorGUILayout.Space(5);
}
private void DrawActionButtons()
{
GUI.enabled = selectedFiles.Count > 0;
GUI.backgroundColor = new Color(0.3f, 0.8f, 0.3f);
if (GUILayout.Button("✓ Apply Rename", GUILayout.Height(50)))
{
ApplyRename();
}
GUI.backgroundColor = Color.white;
GUI.enabled = true;
}
#endregion
#region File Selection
private void RefreshSelectedFiles()
{
selectedFiles.Clear();
var selected = Selection.objects;
foreach (var obj in selected)
{
string path = AssetDatabase.GetAssetPath(obj);
if (!string.IsNullOrEmpty(path) && !AssetDatabase.IsValidFolder(path))
{
selectedFiles.Add(obj);
}
}
}
private void HandleDragAndDrop(Rect dropArea)
{
Event evt = Event.current;
if (dropArea.Contains(evt.mousePosition))
{
if (evt.type == EventType.DragUpdated)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
evt.Use();
}
else if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (var obj in DragAndDrop.objectReferences)
{
string path = AssetDatabase.GetAssetPath(obj);
if (!string.IsNullOrEmpty(path) && !AssetDatabase.IsValidFolder(path))
{
if (!selectedFiles.Contains(obj))
{
selectedFiles.Add(obj);
}
}
}
evt.Use();
}
}
}
#endregion
#region Naming Logic
private string GenerateNewName(string originalName, int index)
{
string baseName = originalName;
string result = "";
switch (namingMode)
{
case NamingMode.Suffix:
result = baseName + separator + customText;
break;
case NamingMode.Prefix:
result = customText + separator + baseName;
break;
case NamingMode.Replace:
string number = (startNumber + index).ToString().PadLeft(numberPadding, '0');
result = customText + separator + number;
break;
case NamingMode.Sequential:
string seqNumber = (startNumber + index).ToString().PadLeft(numberPadding, '0');
result = customText + seqNumber;
break;
}
// Remove invalid characters
result = string.Join("_", result.Split(Path.GetInvalidFileNameChars()));
return result;
}
private void ApplyRename()
{
if (selectedFiles.Count == 0) return;
int successCount = 0;
int failCount = 0;
AssetDatabase.StartAssetEditing();
try
{
for (int i = 0; i < selectedFiles.Count; i++)
{
var file = selectedFiles[i];
if (file == null) continue;
string assetPath = AssetDatabase.GetAssetPath(file);
string directory = Path.GetDirectoryName(assetPath);
string extension = Path.GetExtension(assetPath);
string oldName = file.name;
string newName = GenerateNewName(oldName, i);
string newPath = Path.Combine(directory, newName + extension);
// Check if file already exists
if (File.Exists(newPath) && assetPath != newPath)
{
Debug.LogWarning($"Skipped (exists): {oldName}");
failCount++;
continue;
}
// Rename asset
string error = AssetDatabase.RenameAsset(assetPath, newName);
if (string.IsNullOrEmpty(error))
{
Debug.Log($"✓ {oldName} → {newName}");
successCount++;
}
else
{
Debug.LogError($"✗ {oldName}: {error}");
failCount++;
}
}
}
finally
{
AssetDatabase.StopAssetEditing();
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
Debug.Log($"<b>Rename Complete:</b> {successCount} success, {failCount} failed");
// Clear selection
selectedFiles.Clear();
}
#endregion
#region Presets
private void SaveCurrentAsPreset()
{
var preset = new NamingPreset
{
presetName = newPresetName,
mode = namingMode,
customText = customText,
startNumber = startNumber,
numberPadding = numberPadding,
separator = separator
};
presets.Add(preset);
SavePresets();
Debug.Log($"Preset saved: {newPresetName}");
}
private void LoadPreset(int index)
{
if (index < 0 || index >= presets.Count) return;
var preset = presets[index];
namingMode = preset.mode;
customText = preset.customText;
startNumber = preset.startNumber;
numberPadding = preset.numberPadding;
separator = preset.separator;
Debug.Log($"Preset loaded: {preset.presetName}");
}
private void SavePresets()
{
string json = JsonUtility.ToJson(new PresetList { presets = presets }, true);
EditorPrefs.SetString("MotionCaptureFileRenamer_Presets", json);
}
private void LoadPresets()
{
string json = EditorPrefs.GetString("MotionCaptureFileRenamer_Presets", "");
if (!string.IsNullOrEmpty(json))
{
try
{
var presetList = JsonUtility.FromJson<PresetList>(json);
presets = presetList.presets ?? new List<NamingPreset>();
}
catch
{
presets = new List<NamingPreset>();
}
}
}
[Serializable]
private class PresetList
{
public List<NamingPreset> presets = new List<NamingPreset>();
}
#endregion
}