using System; using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.UI; using VketCloudGUITools.Utilities; using YagihataItems.YagiUtils; namespace VketCloudGUITools.Editor { public enum AutoFixTag { /// /// 自動修正が適応できません /// CanNotAutoFix, /// /// 自動適応不可 /// CanNotAutoApply, /// /// 致命的なエラー。Exportができません。 /// Critical, /// /// 自動修正は(Heliodorにとって)副作用の無い変更を行います。 /// Safe, /// /// 自動修正は、肉眼で確認可能な変更をする可能性があります。 /// MajorChange, /// /// 自動修正はヒエラルキーの変更を行います /// Hierarchical, /// /// 自動修正はアニメーション関係の変更を行います /// Animation, /// /// 自動修正はComponentの削除を行います。 /// RemoveComponent, /// /// レイヤーの自動生成を行います。 /// AutoGenerateLayer, } public class AutoFixErrorHelper { private VCEditorCanvasExporter _exporter = null; private AutoFixCanvasErrorHelper _canvas = null; private AutoFixLayerErrorHelper _layer = null; private AutoFixContentErrorHelper _content = null; private AutoFixTextErrorHelper _text = null; private AutoFixButtonErrorHelper _button = null; private AutoFixSliderErrorHelper _slider = null; private AutoFixGraphicErrorHelper _graphic = null; private AutoFixMaslableGraphicErrorHelper _maskableGraphic = null; private AutoFixSelectableErrorHelper _selectable = null; private AutoFixMiscErrorHelper _misc = null; public AutoFixCanvasErrorHelper Canvas => _canvas; public AutoFixLayerErrorHelper Layer => _layer; public AutoFixContentErrorHelper Content => _content; public AutoFixTextErrorHelper Text => _text; public AutoFixButtonErrorHelper Button => _button; public AutoFixSliderErrorHelper Slider => _slider; public AutoFixGraphicErrorHelper Graphic => _graphic; public AutoFixMaslableGraphicErrorHelper MaskableGraphic => _maskableGraphic; public AutoFixSelectableErrorHelper Selectable => _selectable; public AutoFixMiscErrorHelper Misc => _misc; public AutoFixErrorHelper(VCEditorCanvasExporter exporter) { _exporter = exporter; _canvas = new AutoFixCanvasErrorHelper(this); _layer = new AutoFixLayerErrorHelper(this); _content = new AutoFixContentErrorHelper(this); _text = new AutoFixTextErrorHelper(this); _button = new AutoFixButtonErrorHelper(this); _slider = new AutoFixSliderErrorHelper(this); _graphic = new AutoFixGraphicErrorHelper(this); _maskableGraphic = new AutoFixMaslableGraphicErrorHelper(this); _selectable = new AutoFixSelectableErrorHelper(this); _misc = new AutoFixMiscErrorHelper(this); } public bool ButtonAutoFix(params AutoFixTag[] tags) { bool autoApply = _exporter.AutoApplyAutoFix(tags); EditorGUILayout.BeginVertical(); if (tags != null && tags.Length > 0) { GUILayout.Label(tags.Select(t => t.ToString()).Aggregate((l, r) => $"{l}, {r}"), GUILayout.ExpandWidth(false)); } var retval = autoApply || GUILayout.Button("Auto Fix", GUILayout.ExpandWidth(false)); EditorGUILayout.EndVertical(); return retval; } public void AutoFixNotification(string message) { _exporter.ShowNotification(new GUIContent(message), 3f); } public void AutoFixResolved() { _exporter.OnAutoFixResolved(); } public void AddCriticalMessages(string message, UnityEngine.Object obj, Action onDrawAutoFixButton = null) { _exporter.AddCriticalMessages(message, obj, onDrawAutoFixButton); } public void AddErrorMessage(string message, UnityEngine.Object obj, Action onDrawAutoFixButton = null) { _exporter.AddErrorMessage(message, obj, onDrawAutoFixButton); } public void AddWarningMessage(string message, UnityEngine.Object obj, Action onDrawAutoFixButton = null) { _exporter.AddWarningMessage(message, obj, onDrawAutoFixButton); } } public class AutoFixContentErrorHelper { private AutoFixErrorHelper _helper; private AutoFixContentErrorHelper() { } public AutoFixContentErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action RemoveComponent(Component component) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.RemoveComponent)) { Undo.DestroyObjectImmediate(component); _helper.AutoFixNotification("[Auto Fix] Contentの非対応のComponentを削除"); _helper.AutoFixResolved(); } }; } public Action MoveToParent(Transform contentChild) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Hierarchical)) { Undo.SetTransformParent(contentChild, contentChild.parent.parent, "(Auto Fix) Content Child"); _helper.AutoFixNotification("[Auto Fix] Contentの入れ子構造を解消"); _helper.AutoFixResolved(); } }; } public Action Anchor(RectTransform content) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(content, "(Auto Fix) Content"); content.SetAnchorWithKeepingPosition(new Vector2(0.5f, 0.5f)); _helper.AutoFixNotification("[Auto Fix] ContentのanchorをCenterMiddleに修正"); _helper.AutoFixResolved(); } }; } } public class AutoFixMiscErrorHelper { private AutoFixErrorHelper _helper; private AutoFixMiscErrorHelper() { } public AutoFixMiscErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } /// /// MainTextureが自動修正できない /// /// /// public Action MainTexture(Image image) { return () => { EditorGUILayout.HelpBox("Source Imageを差し替えてください。\nもしくは、(None)にしても出力が可能になります。", MessageType.Info); }; } /// /// Canvas直下にRectTransformではないものが来た場合の自動修正提案 /// /// /// public Action RemoveOrConvertToRectTransform(Transform child) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.CanNotAutoApply)) { int selection = EditorUtility.DisplayDialogComplex("Auto Fix", $"{child.name}をRectTransformに自動変換しますか?\nそれとも削除しますか?", "変換(残す)", "後で", "削除"); switch (selection) { /// 変換(残す) case 0: Undo.AddComponent(child.gameObject); _helper.AutoFixNotification("[Auto Fix] RectTransformに変換"); _helper.AutoFixResolved(); break; /// 後で case 1: // do nothing break; /// 削除 case 2: Undo.DestroyObjectImmediate(child.gameObject); _helper.AutoFixNotification("[Auto Fix] 不要なGameObjectを削除"); _helper.AutoFixResolved(); break; } } }; } } public class AutoFixCanvasErrorHelper { private AutoFixErrorHelper _helper; private AutoFixCanvasErrorHelper() { } public AutoFixCanvasErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action SortingOrder(Canvas canvas) { return () => { if (_helper.ButtonAutoFix()) { Undo.RecordObject(canvas, "(Auto Fix) Canvas"); canvas.sortingOrder = 0; _helper.AutoFixNotification("[Auto Fix] CanvasのSorting Orderをリセット"); _helper.AutoFixResolved(); } }; } public Action MoveChildToAutoGeneratedLayer(Transform child, Canvas targetCanvas, Runtime.VCLayerList autoGeneratedLayerList, Action setAutoGeneratedLayerList) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.AutoGenerateLayer)) { if (autoGeneratedLayerList == null) { bool ok = EditorUtility.DisplayDialog("確認", "Layerの移動先が未指定です。\n手動で設定する場合は「キャンセル」して\n「Auto Generated Layer」項目を指定してください。\nもしくは、この場でレイヤーを自動生成してください。", "レイヤーを自動生成", "キャンセル"); if (ok) { autoGeneratedLayerList = Runtime.VCFactory.CreateLayerList("AutoGeneratedLayer", Runtime.CanvasType.LandScape).GetComponent(); autoGeneratedLayerList.transform.SetParent(targetCanvas.transform, worldPositionStays: false); autoGeneratedLayerList.transform.localPosition = Vector3.zero; autoGeneratedLayerList.transform.localRotation = Quaternion.identity; autoGeneratedLayerList.transform.localScale = Vector3.one; setAutoGeneratedLayerList(autoGeneratedLayerList); _helper.AutoFixNotification("[Auto Fix] Auto Generated Layerを生成。もういちど[Auto Fix]で自動配置。"); Undo.RegisterCreatedObjectUndo(autoGeneratedLayerList.gameObject, "(Auto Fix) Generate Auto Layer"); } else { _helper.AutoFixNotification("[Auto Generated Layer]を手動設定してください。"); } } else { Undo.SetTransformParent(child, autoGeneratedLayerList.transform, "(Auto Fix) Move Layer"); _helper.AutoFixNotification("[Auto Fix] Auto Generated Layerに再配置"); _helper.AutoFixResolved(); } } }; } public Action RemoveComponent(Component component) { return () => { if (_helper.ButtonAutoFix()) { Undo.DestroyObjectImmediate(component); _helper.AutoFixNotification("[Auto Fix] Canvasの不要なComponentを削除"); _helper.AutoFixResolved(); } }; } public Action PixelPerfect(Canvas canvas) { return () => { if (_helper.ButtonAutoFix()) { Undo.RecordObject(canvas, "(Auto Fix) Canvas"); canvas.pixelPerfect = false; _helper.AutoFixNotification("[Auto Fix] CanvasのPixel Perfectをリセット"); _helper.AutoFixResolved(); } }; } public Action AdditionalShaderCannels(Canvas canvas) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(canvas, "(Auto Fix) Canvas"); canvas.additionalShaderChannels = AdditionalCanvasShaderChannels.None; _helper.AutoFixNotification("[Auto Fix] CanvasのAdditional Shader Channelsをリセット"); _helper.AutoFixResolved(); } }; } } public class AutoFixLayerErrorHelper { private AutoFixErrorHelper _helper; private AutoFixLayerErrorHelper() { } public AutoFixLayerErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action RemoveComponent(Component component) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.RemoveComponent)) { Undo.DestroyObjectImmediate(component); _helper.AutoFixNotification("[Auto Fix] Layerの非対応のComponentを削除"); _helper.AutoFixResolved(); } }; } public Action Anchor(RectTransform layer) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(layer, "(Auto Fix) Layer"); layer.SetAnchorWithKeepingPosition(0f, 0f, 1f, 1f); _helper.AutoFixNotification("[Auto Fix] LayerのanchorをStretchに修正"); _helper.AutoFixResolved(); } }; } public Action SizeDelta(RectTransform layer) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RecordObject(layer, "(Auto Fix) Layer"); layer.anchoredPosition = new Vector2(0f, 0f); layer.sizeDelta = new Vector2(0f, 0f); _helper.AutoFixNotification("[Auto Fix] LayerのLeft/Top/Right/Bottomをリセット"); _helper.AutoFixResolved(); } }; } public Action AddLayerListComponent(RectTransform layer) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.AddComponent(layer.gameObject); _helper.AutoFixNotification("[Auto Fix] LayerにVCGUILayerListコンポーネントを追加"); _helper.AutoFixResolved(); } }; } } public class AutoFixButtonErrorHelper { private AutoFixErrorHelper _helper; private AutoFixButtonErrorHelper() { } public AutoFixButtonErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action DisabledSprite(Button button) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(button, "(Auto Fix) Button"); var temp = button.spriteState; temp.disabledSprite = null; button.spriteState = temp; _helper.AutoFixNotification("[Auto Fix] ButtonのDisabled Spriteをリセット"); _helper.AutoFixResolved(); } }; } public Action PressedSprite(Button button) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(button, "(Auto Fix) Button"); var temp = button.spriteState; temp.pressedSprite = null; button.spriteState = temp; _helper.AutoFixNotification("[Auto Fix] ButtonのPressed Spriteをリセット"); _helper.AutoFixResolved(); } }; } public Action AddTextComponent(Button button) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.AddComponent(button.gameObject); _helper.AutoFixNotification("[Auto Fix] ButtonにImageを追加"); _helper.AutoFixResolved(); } }; } public Action TargetGraphic(Button button) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RecordObject(button, "(Auto Fix) Button"); button.targetGraphic = button.GetComponent(); _helper.AutoFixNotification("[Auto Fix] ButtonのTarget Graphicを修正"); _helper.AutoFixResolved(); } }; } public Action Transition(Button button) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange, AutoFixTag.Animation)) { Undo.RecordObject(button, "(Auto Fix) Button"); button.transition = Selectable.Transition.SpriteSwap; _helper.AutoFixNotification("[Auto Fix] ButtonのTransitionを修正"); _helper.AutoFixResolved(); } }; } } public class AutoFixMaslableGraphicErrorHelper { private AutoFixErrorHelper _helper; private AutoFixMaslableGraphicErrorHelper() { } public AutoFixMaslableGraphicErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action Maskable(MaskableGraphic maskableGraphic, string tag) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(maskableGraphic, $"(Auto Fix) {tag}"); maskableGraphic.maskable = true; _helper.AutoFixNotification($"[Auto Fix] {tag}のMaskableを修正"); _helper.AutoFixResolved(); } }; } } public class AutoFixSelectableErrorHelper { private AutoFixErrorHelper _helper; private AutoFixSelectableErrorHelper() { } public AutoFixSelectableErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action Navigation(Selectable selectable, string tag) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(selectable, $"(Auto Fix) {tag}"); var temp = selectable.navigation; temp.mode = UnityEngine.UI.Navigation.Mode.Automatic; selectable.navigation = temp; _helper.AutoFixNotification($"[Auto Fix] {tag}のNavigationをリセット"); _helper.AutoFixResolved(); } }; } } public class AutoFixGraphicErrorHelper { private AutoFixErrorHelper _helper; private AutoFixGraphicErrorHelper() { } public AutoFixGraphicErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action RaycastTarget(Graphic graphic, string tag) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(graphic, $"(Auto Fix) {tag}"); graphic.raycastTarget = true; _helper.AutoFixNotification($"[Auto Fix] {tag}eのRaycast Targetをリセット"); _helper.AutoFixResolved(); } }; } } public class AutoFixSliderErrorHelper { private AutoFixErrorHelper _helper; private AutoFixSliderErrorHelper() { } public AutoFixSliderErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action HandleSlideAreaPositionSize(RectTransform handleSlideArea) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RecordObject(handleSlideArea, "(Auto Fix) Slider Handle Slide Area"); handleSlideArea.SetPivotWithKeepingPosition(VectorUtility.half2D); handleSlideArea.anchoredPosition = Vector2.zero; handleSlideArea.sizeDelta = Vector2.zero; _helper.AutoFixNotification("[Auto Fix] SliderのHandle Slide AreaのAnchord Position/Size Deltaをリセット"); _helper.AutoFixResolved(); } }; } public Action HandleSlideAreaPivot(RectTransform handleSlideArea) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(handleSlideArea, "(Auto Fix) Slider Handle Slide Area"); handleSlideArea.SetPivotWithKeepingPosition(VectorUtility.half2D); _helper.AutoFixNotification("[Auto Fix] SliderのHandle Slide AreaのPivotをMiddleCenterに修正"); _helper.AutoFixResolved(); } }; } public Action HandleSlideAreaErrorAnchor(RectTransform handleSlideArea) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(handleSlideArea, "(Auto Fix) Slider Handle Slide Area"); handleSlideArea.SetAnchorWithKeepingPosition(0f, 0.5f, 1f, 0.5f); _helper.AutoFixNotification("[Auto Fix] SliderのHandle Slide AreaのAnchorをMiddleStrecthに修正"); _helper.AutoFixResolved(); } }; } public Action FillAreaErrorPivot(RectTransform fillArea) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(fillArea, "(Auto Fix) Slider Fill Area"); fillArea.SetPivotWithKeepingPosition(VectorUtility.half2D); _helper.AutoFixNotification("[Auto Fix] SliderのFill AreaのPivotをMiddleCenterに修正"); _helper.AutoFixResolved(); } }; } public Action FillAreaErrorAnchor(RectTransform fillArea) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(fillArea, "(Auto Fix) Slider Fill Area"); fillArea.SetAnchorWithKeepingPosition(Vector2.zero, Vector2.one); _helper.AutoFixNotification("[Auto Fix] SliderのFill AreaのAnchorをStrecthに修正"); _helper.AutoFixResolved(); } }; } public Action Value(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RegisterFullObjectHierarchyUndo(slider, "(Auto Fix) Slider"); slider.value = 0f; _helper.AutoFixNotification("[Auto Fix] SliderのValueを修正"); _helper.AutoFixResolved(); } }; } public Action WholeNumbers(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RegisterFullObjectHierarchyUndo(slider, "(Auto Fix) Slider"); slider.wholeNumbers = false; _helper.AutoFixNotification("[Auto Fix] SliderのWhole Numbersを修正"); _helper.AutoFixResolved(); } }; } public Action MaxValue(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RegisterFullObjectHierarchyUndo(slider, "(Auto Fix) Slider"); slider.maxValue = 1f; _helper.AutoFixNotification("[Auto Fix] SliderのMax Valueを修正"); _helper.AutoFixResolved(); } }; } public Action MinValue(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RegisterFullObjectHierarchyUndo(slider, "(Auto Fix) Slider"); slider.minValue = 0f; _helper.AutoFixNotification("[Auto Fix] SliderのMin Valueを修正"); _helper.AutoFixResolved(); } }; } public Action Direction(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange, AutoFixTag.Critical)) { Undo.RegisterFullObjectHierarchyUndo(slider, "(Auto Fix) Slider"); slider.SetDirection(Slider.Direction.LeftToRight, includeRectLayouts: false); _helper.AutoFixNotification("[Auto Fix] SliderのDirectionをLeft To Rightに修正"); _helper.AutoFixResolved(); } }; } public Action Transition(Slider slider) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange, AutoFixTag.Animation)) { Undo.RecordObject(slider, "(Auto Fix) Slider"); slider.transition = Selectable.Transition.SpriteSwap; _helper.AutoFixNotification("[Auto Fix] SliderのTransitionをSpriteSwapに修正"); _helper.AutoFixResolved(); } }; } public Action UnableToAutoFix(Slider slider) { return () => { EditorGUILayout.HelpBox("Sliderは複雑な破損の仕方をしているため、自動修正ができません。\n可能ならば手動で修正してください。\nもしくは、新しくSliderを作り直してください。", MessageType.Error); }; } } public class AutoFixTextErrorHelper { private AutoFixErrorHelper _helper; private AutoFixTextErrorHelper() { } public AutoFixTextErrorHelper(AutoFixErrorHelper helper) { _helper = helper; } public Action BestFit(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.resizeTextForBestFit = false; _helper.AutoFixNotification("[Auto Fix] TextのBest Fitを無効化"); _helper.AutoFixResolved(); } }; } public Action VerticalOverflow(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.verticalOverflow = VerticalWrapMode.Truncate; _helper.AutoFixNotification("[Auto Fix] TextのVertical Overflowを修正"); _helper.AutoFixResolved(); } }; } public Action HorizontalOverflow(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.horizontalOverflow = HorizontalWrapMode.Wrap; _helper.AutoFixNotification("[Auto Fix] TextのHorizontal Overflowを修正"); _helper.AutoFixResolved(); } }; } public Action AlignByGeometry(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.alignByGeometry = false; _helper.AutoFixNotification("[Auto Fix] TextのAlign By Geometryを無効化"); _helper.AutoFixResolved(); } }; } public Action Alignment(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.MajorChange)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.alignment = TextAnchor.UpperLeft; _helper.AutoFixNotification("[Auto Fix] TextのAlignmentをUpperLeftに修正"); _helper.AutoFixResolved(); } }; } public Action RichText(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.supportRichText = false; _helper.AutoFixNotification("[Auto Fix] TextのRich Textをデフォルトに修正"); _helper.AutoFixResolved(); } }; } public Action LineSpacing(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.lineSpacing = 1; _helper.AutoFixNotification("[Auto Fix] TextのLine Spacingをデフォルトに修正"); _helper.AutoFixResolved(); } }; } public Action TextStyle(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.fontStyle = FontStyle.Normal; _helper.AutoFixNotification("[Auto Fix] TextのTextSyleをデフォルトに修正"); _helper.AutoFixResolved(); } }; } public Action Font(Text text) { return () => { if (_helper.ButtonAutoFix(AutoFixTag.Safe)) { Undo.RecordObject(text, "(Auto Fix) Text"); text.font = Resources.GetBuiltinResource("Arial.ttf"); _helper.AutoFixNotification("[Auto Fix] TextのFontをデフォルトに修正"); _helper.AutoFixResolved(); } }; } } }