Broken UI system
This commit is contained in:
446
Editor/Inspectors/PSXUIEditors.cs
Normal file
446
Editor/Inspectors/PSXUIEditors.cs
Normal file
@@ -0,0 +1,446 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using SplashEdit.RuntimeCode;
|
||||
|
||||
namespace SplashEdit.EditorCode
|
||||
{
|
||||
// ─── Scene Preview Gizmos ───
|
||||
// These draw filled rectangles in the Scene view for WYSIWYG UI preview.
|
||||
|
||||
public static class PSXUIGizmos
|
||||
{
|
||||
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
|
||||
static void DrawBoxGizmo(PSXUIBox box, GizmoType gizmoType)
|
||||
{
|
||||
RectTransform rt = box.GetComponent<RectTransform>();
|
||||
if (rt == null) return;
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rt.GetWorldCorners(corners);
|
||||
Color fill = box.BoxColor;
|
||||
fill.a = (gizmoType & GizmoType.Selected) != 0 ? 0.8f : 0.5f;
|
||||
Color border = Color.white;
|
||||
border.a = (gizmoType & GizmoType.Selected) != 0 ? 1f : 0.4f;
|
||||
Handles.DrawSolidRectangleWithOutline(corners, fill, border);
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
|
||||
static void DrawImageGizmo(PSXUIImage image, GizmoType gizmoType)
|
||||
{
|
||||
RectTransform rt = image.GetComponent<RectTransform>();
|
||||
if (rt == null) return;
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rt.GetWorldCorners(corners);
|
||||
|
||||
bool selected = (gizmoType & GizmoType.Selected) != 0;
|
||||
|
||||
// Draw texture preview if available
|
||||
if (image.SourceTexture != null)
|
||||
{
|
||||
Color tint = image.TintColor;
|
||||
tint.a = selected ? 0.9f : 0.6f;
|
||||
Handles.DrawSolidRectangleWithOutline(corners, tint * 0.3f, tint);
|
||||
|
||||
// Draw texture in GUI overlay
|
||||
Handles.BeginGUI();
|
||||
Vector2 min = HandleUtility.WorldToGUIPoint(corners[0]);
|
||||
Vector2 max = HandleUtility.WorldToGUIPoint(corners[2]);
|
||||
Rect screenRect = new Rect(
|
||||
Mathf.Min(min.x, max.x), Mathf.Min(min.y, max.y),
|
||||
Mathf.Abs(max.x - min.x), Mathf.Abs(max.y - min.y));
|
||||
if (screenRect.width > 2 && screenRect.height > 2)
|
||||
{
|
||||
GUI.color = new Color(tint.r, tint.g, tint.b, selected ? 0.9f : 0.5f);
|
||||
GUI.DrawTexture(screenRect, image.SourceTexture, ScaleMode.StretchToFill);
|
||||
GUI.color = Color.white;
|
||||
}
|
||||
Handles.EndGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
Color fill = new Color(0.4f, 0.4f, 0.8f, selected ? 0.4f : 0.2f);
|
||||
Handles.DrawSolidRectangleWithOutline(corners, fill, Color.cyan);
|
||||
}
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
|
||||
static void DrawTextGizmo(PSXUIText text, GizmoType gizmoType)
|
||||
{
|
||||
RectTransform rt = text.GetComponent<RectTransform>();
|
||||
if (rt == null) return;
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rt.GetWorldCorners(corners);
|
||||
|
||||
bool selected = (gizmoType & GizmoType.Selected) != 0;
|
||||
Color border = text.TextColor;
|
||||
border.a = selected ? 1f : 0.5f;
|
||||
Color fill = new Color(0, 0, 0, selected ? 0.3f : 0.1f);
|
||||
Handles.DrawSolidRectangleWithOutline(corners, fill, border);
|
||||
|
||||
// Draw text preview at actual PSX glyph size.
|
||||
// On the PS1, chainprintf renders each glyph top-left aligned at the
|
||||
// element's position — no centering. Mimic that here.
|
||||
string label = string.IsNullOrEmpty(text.DefaultText) ? "[empty]" : text.DefaultText;
|
||||
|
||||
PSXFontAsset font = text.GetEffectiveFont();
|
||||
int glyphW = font != null ? font.GlyphWidth : 8;
|
||||
int glyphH = font != null ? font.GlyphHeight : 16;
|
||||
|
||||
Handles.BeginGUI();
|
||||
// Convert top-left corner (corners[1] in Unity is top-left after GetWorldCorners)
|
||||
Vector2 topLeft = HandleUtility.WorldToGUIPoint(corners[1]);
|
||||
Vector2 botRight = HandleUtility.WorldToGUIPoint(corners[3]);
|
||||
|
||||
// Calculate pixel scale: how many screen pixels represent one PSX pixel
|
||||
float rectWorldW = Vector3.Distance(corners[0], corners[3]);
|
||||
float rectScreenW = Mathf.Abs(botRight.x - topLeft.x);
|
||||
float rectW = rt.rect.width;
|
||||
float psxPixelScale = (rectW > 0.01f) ? rectScreenW / rectW : 1f;
|
||||
|
||||
float charScreenW = glyphW * psxPixelScale;
|
||||
float charScreenH = glyphH * psxPixelScale;
|
||||
int fontSize = Mathf.Clamp(Mathf.RoundToInt(charScreenH * 0.75f), 6, 72);
|
||||
|
||||
GUIStyle style = new GUIStyle(EditorStyles.label);
|
||||
style.normal.textColor = text.TextColor;
|
||||
style.alignment = TextAnchor.UpperLeft;
|
||||
style.fontSize = fontSize;
|
||||
style.wordWrap = false;
|
||||
style.clipping = TextClipping.Clip;
|
||||
style.padding = new RectOffset(0, 0, 0, 0);
|
||||
|
||||
// Render position = top-left of the rect (matching PSX chainprintf behavior)
|
||||
float guiW = Mathf.Abs(botRight.x - topLeft.x);
|
||||
float guiH = Mathf.Abs(botRight.y - topLeft.y);
|
||||
Rect guiRect = new Rect(
|
||||
Mathf.Min(topLeft.x, botRight.x),
|
||||
Mathf.Min(topLeft.y, botRight.y),
|
||||
guiW, guiH);
|
||||
|
||||
GUI.color = new Color(text.TextColor.r, text.TextColor.g, text.TextColor.b, selected ? 1f : 0.7f);
|
||||
GUI.Label(guiRect, label, style);
|
||||
GUI.color = Color.white;
|
||||
Handles.EndGUI();
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
|
||||
static void DrawProgressBarGizmo(PSXUIProgressBar bar, GizmoType gizmoType)
|
||||
{
|
||||
RectTransform rt = bar.GetComponent<RectTransform>();
|
||||
if (rt == null) return;
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rt.GetWorldCorners(corners);
|
||||
|
||||
bool selected = (gizmoType & GizmoType.Selected) != 0;
|
||||
|
||||
// Background
|
||||
Color bgColor = bar.BackgroundColor;
|
||||
bgColor.a = selected ? 0.8f : 0.5f;
|
||||
Handles.DrawSolidRectangleWithOutline(corners, bgColor, Color.white * (selected ? 1f : 0.4f));
|
||||
|
||||
// Fill portion
|
||||
float t = bar.InitialValue / 100f;
|
||||
if (t > 0.001f)
|
||||
{
|
||||
Vector3[] fillCorners = new Vector3[4];
|
||||
fillCorners[0] = corners[0]; // bottom-left
|
||||
fillCorners[1] = corners[1]; // top-left
|
||||
fillCorners[2] = Vector3.Lerp(corners[1], corners[2], t); // top-right (partial)
|
||||
fillCorners[3] = Vector3.Lerp(corners[0], corners[3], t); // bottom-right (partial)
|
||||
Color fillColor = bar.FillColor;
|
||||
fillColor.a = selected ? 0.9f : 0.6f;
|
||||
Handles.DrawSolidRectangleWithOutline(fillCorners, fillColor, Color.clear);
|
||||
}
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
|
||||
static void DrawCanvasGizmo(PSXCanvas canvas, GizmoType gizmoType)
|
||||
{
|
||||
RectTransform rt = canvas.GetComponent<RectTransform>();
|
||||
if (rt == null) return;
|
||||
Vector3[] corners = new Vector3[4];
|
||||
rt.GetWorldCorners(corners);
|
||||
bool selected = (gizmoType & GizmoType.Selected) != 0;
|
||||
Color border = selected ? Color.yellow : new Color(1, 1, 0, 0.3f);
|
||||
Handles.DrawSolidRectangleWithOutline(corners, Color.clear, border);
|
||||
|
||||
// Label
|
||||
if (selected)
|
||||
{
|
||||
Vector2 res = PSXCanvas.PSXResolution;
|
||||
Vector3 topMid = (corners[1] + corners[2]) * 0.5f;
|
||||
string label = $"PSX Canvas: {canvas.CanvasName} ({res.x}x{res.y})";
|
||||
GUIStyle style = new GUIStyle(EditorStyles.boldLabel);
|
||||
style.normal.textColor = Color.yellow;
|
||||
Handles.Label(topMid, label, style);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXCanvas component.
|
||||
/// Shows canvas name, visibility, sort order, font, and a summary of child elements.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXCanvas))]
|
||||
public class PSXCanvasEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
Vector2 res = PSXCanvas.PSXResolution;
|
||||
EditorGUILayout.LabelField($"PSX Canvas ({res.x}x{res.y})", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("canvasName"), new GUIContent("Canvas Name",
|
||||
"Name used from Lua: UI.FindCanvas(\"name\"). Max 24 chars."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"), new GUIContent("Start Visible",
|
||||
"Whether the canvas is visible when the scene loads."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("sortOrder"), new GUIContent("Sort Order",
|
||||
"Render priority (0 = back, 255 = front)."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultFont"), new GUIContent("Default Font",
|
||||
"Default custom font for text elements. If empty, uses built-in system font (8x16)."));
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// Force Canvas configuration button
|
||||
if (GUILayout.Button($"Reset Canvas to {res.x}x{res.y}"))
|
||||
{
|
||||
PSXCanvas.InvalidateResolutionCache();
|
||||
((PSXCanvas)target).ConfigureCanvas();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// Element summary
|
||||
PSXCanvas canvas = (PSXCanvas)target;
|
||||
int imageCount = canvas.GetComponentsInChildren<PSXUIImage>(true).Length;
|
||||
int boxCount = canvas.GetComponentsInChildren<PSXUIBox>(true).Length;
|
||||
int textCount = canvas.GetComponentsInChildren<PSXUIText>(true).Length;
|
||||
int progressCount = canvas.GetComponentsInChildren<PSXUIProgressBar>(true).Length;
|
||||
int total = imageCount + boxCount + textCount + progressCount;
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
$"Elements: {total} total\n" +
|
||||
$" Images: {imageCount} | Boxes: {boxCount}\n" +
|
||||
$" Texts: {textCount} | Progress Bars: {progressCount}",
|
||||
total > 128 ? MessageType.Warning : MessageType.Info);
|
||||
|
||||
if (total > 128)
|
||||
EditorGUILayout.HelpBox("PS1 UI system supports max 128 elements total across all canvases.", MessageType.Error);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXUIImage component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXUIImage))]
|
||||
public class PSXUIImageEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField("PSX UI Image", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("elementName"), new GUIContent("Element Name",
|
||||
"Name used from Lua: UI.FindElement(canvas, \"name\"). Max 24 chars."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("sourceTexture"), new GUIContent("Source Texture",
|
||||
"Texture to quantize and pack into VRAM."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("bitDepth"), new GUIContent("Bit Depth",
|
||||
"VRAM storage depth. 4-bit = 16 colors, 8-bit = 256 colors, 16-bit = direct color."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("tintColor"), new GUIContent("Tint Color",
|
||||
"Color multiply applied to the image (white = no tint)."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"));
|
||||
|
||||
// Texture size warning
|
||||
PSXUIImage img = (PSXUIImage)target;
|
||||
if (img.SourceTexture != null)
|
||||
{
|
||||
if (img.SourceTexture.width > 256 || img.SourceTexture.height > 256)
|
||||
EditorGUILayout.HelpBox("Texture exceeds 256×256. It will be resized during export.", MessageType.Warning);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXUIBox component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXUIBox))]
|
||||
public class PSXUIBoxEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField("PSX UI Box", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("elementName"));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("boxColor"), new GUIContent("Box Color",
|
||||
"Solid fill color rendered as a FastFill primitive."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"));
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXUIText component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXUIText))]
|
||||
public class PSXUITextEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField("PSX UI Text", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("elementName"));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultText"), new GUIContent("Default Text",
|
||||
"Initial text content. Max 63 chars. Change at runtime via UI.SetText()."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("textColor"), new GUIContent("Text Color",
|
||||
"Text render color."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("fontOverride"), new GUIContent("Font Override",
|
||||
"Custom font for this text element. If empty, uses the canvas default font or built-in system font (8x16)."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"));
|
||||
|
||||
// Character count
|
||||
PSXUIText txt = (PSXUIText)target;
|
||||
if (!string.IsNullOrEmpty(txt.DefaultText) && txt.DefaultText.Length > 63)
|
||||
EditorGUILayout.HelpBox("Text exceeds 63 characters and will be truncated.", MessageType.Warning);
|
||||
|
||||
// Font info
|
||||
PSXFontAsset font = txt.GetEffectiveFont();
|
||||
if (font != null)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
$"Font: {font.name} ({font.GlyphWidth}x{font.GlyphHeight} glyphs)",
|
||||
MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Using built-in system font (8x16 glyphs).", MessageType.Info);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXUIProgressBar component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXUIProgressBar))]
|
||||
public class PSXUIProgressBarEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField("PSX UI Progress Bar", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("elementName"));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("backgroundColor"), new GUIContent("Background Color",
|
||||
"Color shown behind the fill bar."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("fillColor"), new GUIContent("Fill Color",
|
||||
"Color of the progress fill."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("initialValue"), new GUIContent("Initial Value",
|
||||
"Starting progress (0-100). Change via UI.SetProgress()."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"));
|
||||
|
||||
// Preview bar
|
||||
Rect r = EditorGUILayout.GetControlRect(false, 16);
|
||||
PSXUIProgressBar bar = (PSXUIProgressBar)target;
|
||||
EditorGUI.DrawRect(r, bar.BackgroundColor);
|
||||
Rect fill = r;
|
||||
fill.width *= bar.InitialValue / 100f;
|
||||
EditorGUI.DrawRect(fill, bar.FillColor);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom inspector for PSXFontAsset ScriptableObject.
|
||||
/// Shows font metrics, auto-conversion from TTF/OTF, and a preview of the glyph layout.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(PSXFontAsset))]
|
||||
public class PSXFontAssetEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.LabelField("PSX Font Asset", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// Source font (TTF/OTF)
|
||||
EditorGUILayout.LabelField("Auto-Convert from Font", EditorStyles.miniBoldLabel);
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("sourceFont"), new GUIContent("Source Font (TTF/OTF)",
|
||||
"Assign a Unity Font (TrueType/OpenType). Click 'Generate Bitmap' to rasterize it."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("fontSize"), new GUIContent("Font Size",
|
||||
"Pixel height for rasterization. Determines glyph cell height."));
|
||||
|
||||
PSXFontAsset font = (PSXFontAsset)target;
|
||||
if (font.SourceFont != null)
|
||||
{
|
||||
if (GUILayout.Button("Generate Bitmap from Font"))
|
||||
{
|
||||
font.GenerateBitmapFromFont();
|
||||
}
|
||||
|
||||
if (font.FontTexture == null)
|
||||
EditorGUILayout.HelpBox("Click 'Generate Bitmap' to create the font texture.", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(8);
|
||||
|
||||
// Manual bitmap
|
||||
EditorGUILayout.LabelField("Manual Bitmap Source", EditorStyles.miniBoldLabel);
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("fontTexture"), new GUIContent("Font Texture",
|
||||
"256px wide bitmap. Glyphs in ASCII order from 0x20 (space). " +
|
||||
"Transparent = background, opaque = foreground."));
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
// Glyph metrics
|
||||
EditorGUILayout.LabelField("Glyph Metrics", EditorStyles.miniBoldLabel);
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("glyphWidth"), new GUIContent("Glyph Width",
|
||||
"Width of each glyph cell in pixels."));
|
||||
EditorGUILayout.PropertyField(serializedObject.FindProperty("glyphHeight"), new GUIContent("Glyph Height",
|
||||
"Height of each glyph cell in pixels."));
|
||||
|
||||
EditorGUILayout.Space(4);
|
||||
|
||||
int glyphsPerRow = font.GlyphsPerRow;
|
||||
int rowCount = font.RowCount;
|
||||
int totalH = font.TextureHeight;
|
||||
int vramBytes = totalH * 128; // 128 bytes per row at 4bpp 256px
|
||||
|
||||
EditorGUILayout.HelpBox(
|
||||
$"Layout: {glyphsPerRow} glyphs/row, {rowCount} rows\n" +
|
||||
$"Texture: 256 x {totalH} pixels (4bpp)\n" +
|
||||
$"VRAM: {vramBytes} bytes ({vramBytes / 1024f:F1} KB)\n" +
|
||||
$"Glyph size: {font.GlyphWidth} x {font.GlyphHeight}",
|
||||
MessageType.Info);
|
||||
|
||||
if (font.FontTexture != null)
|
||||
{
|
||||
if (font.FontTexture.width != 256)
|
||||
EditorGUILayout.HelpBox($"Font texture must be 256 pixels wide (currently {font.FontTexture.width}).", MessageType.Error);
|
||||
|
||||
// Show preview
|
||||
Rect previewRect = EditorGUILayout.GetControlRect(false, 64);
|
||||
GUI.DrawTexture(previewRect, font.FontTexture, ScaleMode.ScaleToFit);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user