added code from unity
This commit is contained in:
8
Editor.meta
Normal file
8
Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 608491ce009b2494c894080b243698b9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Editor/Jovian.PopupSystem.Editor.asmdef
Normal file
16
Editor/Jovian.PopupSystem.Editor.asmdef
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Jovian.PopupSystem.Editor",
|
||||
"rootNamespace": "Jovian.PopupSystem.Editor",
|
||||
"references": [
|
||||
"Jovian.PopupSystem"
|
||||
],
|
||||
"includePlatforms": ["Editor"],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Editor/Jovian.PopupSystem.Editor.asmdef.meta
Normal file
7
Editor/Jovian.PopupSystem.Editor.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e663435ad13b46d40a29802dab7e52f5
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
104
Editor/PopupCategoryDrawer.cs
Normal file
104
Editor/PopupCategoryDrawer.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem.Editor {
|
||||
[CustomPropertyDrawer(typeof(PopupCategory))]
|
||||
public sealed class PopupCategoryDrawer : PropertyDrawer {
|
||||
private static readonly string[] builtInIds = {
|
||||
"Character",
|
||||
"Item",
|
||||
"Skill",
|
||||
"General"
|
||||
};
|
||||
|
||||
private const string customLabel = "Custom...";
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||
var idProp = FindIdProperty(property);
|
||||
if(idProp == null) {
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
var currentValue = idProp.stringValue ?? "";
|
||||
var isCustom = Array.IndexOf(builtInIds, currentValue) < 0;
|
||||
|
||||
// Two lines when in custom mode: dropdown + text field
|
||||
return isCustom
|
||||
? EditorGUIUtility.singleLineHeight * 2 + 2
|
||||
: EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var idProp = FindIdProperty(property);
|
||||
if(idProp == null) {
|
||||
EditorGUI.LabelField(position, label.text, "Cannot resolve PopupCategory id field");
|
||||
EditorGUI.EndProperty();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentValue = idProp.stringValue ?? "";
|
||||
var builtInIndex = Array.IndexOf(builtInIds, currentValue);
|
||||
var isCustom = builtInIndex < 0 && !string.IsNullOrEmpty(currentValue);
|
||||
|
||||
// Build display options: built-in entries + "Custom..."
|
||||
var options = new List<string>(builtInIds);
|
||||
options.Add(customLabel);
|
||||
|
||||
// Determine selected index
|
||||
int selectedIndex;
|
||||
if(builtInIndex >= 0) {
|
||||
selectedIndex = builtInIndex;
|
||||
}
|
||||
else {
|
||||
selectedIndex = options.Count - 1; // "Custom..."
|
||||
}
|
||||
|
||||
// First line: dropdown
|
||||
var dropdownRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
|
||||
var newIndex = EditorGUI.Popup(dropdownRect, label.text, selectedIndex, options.ToArray());
|
||||
|
||||
if(newIndex != selectedIndex) {
|
||||
if(newIndex < builtInIds.Length) {
|
||||
idProp.stringValue = builtInIds[newIndex];
|
||||
}
|
||||
else {
|
||||
// Switched to custom — seed with a placeholder if currently built-in
|
||||
if(!isCustom) {
|
||||
idProp.stringValue = "NewCategory";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second line: editable text field when custom
|
||||
var finalIsCustom = newIndex >= builtInIds.Length || (newIndex == selectedIndex && isCustom);
|
||||
if(finalIsCustom) {
|
||||
var textRect = new Rect(
|
||||
position.x + EditorGUIUtility.labelWidth + 2,
|
||||
position.y + EditorGUIUtility.singleLineHeight + 2,
|
||||
position.width - EditorGUIUtility.labelWidth - 2,
|
||||
EditorGUIUtility.singleLineHeight);
|
||||
var newValue = EditorGUI.TextField(textRect, idProp.stringValue);
|
||||
if(newValue != idProp.stringValue) {
|
||||
idProp.stringValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private static SerializedProperty FindIdProperty(SerializedProperty property) {
|
||||
// readonly struct with [SerializeField] readonly string id
|
||||
// Unity serializes this as "id" directly
|
||||
var prop = property.FindPropertyRelative("id");
|
||||
if(prop != null) {
|
||||
return prop;
|
||||
}
|
||||
// Fallback: auto-property backing field pattern
|
||||
return property.FindPropertyRelative("<id>k__BackingField");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Editor/PopupCategoryDrawer.cs.meta
Normal file
2
Editor/PopupCategoryDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cc96a089d31fe14cbadf6c59ea0c9aa
|
||||
100
Editor/PopupElementTypeDrawer.cs
Normal file
100
Editor/PopupElementTypeDrawer.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem.Editor {
|
||||
/// <summary>
|
||||
/// Custom PropertyDrawer for <see cref="PopupElementType"/>. Shows a dropdown with
|
||||
/// built-in element types plus a "Custom..." option for free-text entry.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(PopupElementType))]
|
||||
public sealed class PopupElementTypeDrawer : PropertyDrawer {
|
||||
private static readonly string[] builtInIds = {
|
||||
"header",
|
||||
"text",
|
||||
"label_value_text",
|
||||
"image",
|
||||
"separator"
|
||||
};
|
||||
|
||||
private const string customLabel = "Custom...";
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
||||
var idProp = FindIdProperty(property);
|
||||
if(idProp == null) {
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
var currentValue = idProp.stringValue ?? "";
|
||||
var isCustom = Array.IndexOf(builtInIds, currentValue) < 0 && !string.IsNullOrEmpty(currentValue);
|
||||
|
||||
return isCustom
|
||||
? EditorGUIUtility.singleLineHeight * 2 + 2
|
||||
: EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
var idProp = FindIdProperty(property);
|
||||
if(idProp == null) {
|
||||
EditorGUI.LabelField(position, label.text, "Cannot resolve PopupElementType id field");
|
||||
EditorGUI.EndProperty();
|
||||
return;
|
||||
}
|
||||
|
||||
var currentValue = idProp.stringValue ?? "";
|
||||
var builtInIndex = Array.IndexOf(builtInIds, currentValue);
|
||||
var isCustom = builtInIndex < 0 && !string.IsNullOrEmpty(currentValue);
|
||||
|
||||
var options = new List<string>(builtInIds);
|
||||
options.Add(customLabel);
|
||||
|
||||
int selectedIndex;
|
||||
if(builtInIndex >= 0) {
|
||||
selectedIndex = builtInIndex;
|
||||
}
|
||||
else {
|
||||
selectedIndex = options.Count - 1;
|
||||
}
|
||||
|
||||
var dropdownRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
|
||||
var newIndex = EditorGUI.Popup(dropdownRect, label.text, selectedIndex, options.ToArray());
|
||||
|
||||
if(newIndex != selectedIndex) {
|
||||
if(newIndex < builtInIds.Length) {
|
||||
idProp.stringValue = builtInIds[newIndex];
|
||||
}
|
||||
else {
|
||||
if(!isCustom) {
|
||||
idProp.stringValue = "custom_element";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var finalIsCustom = newIndex >= builtInIds.Length || (newIndex == selectedIndex && isCustom);
|
||||
if(finalIsCustom) {
|
||||
var textRect = new Rect(
|
||||
position.x + EditorGUIUtility.labelWidth + 2,
|
||||
position.y + EditorGUIUtility.singleLineHeight + 2,
|
||||
position.width - EditorGUIUtility.labelWidth - 2,
|
||||
EditorGUIUtility.singleLineHeight);
|
||||
var newValue = EditorGUI.TextField(textRect, idProp.stringValue);
|
||||
if(newValue != idProp.stringValue) {
|
||||
idProp.stringValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private static SerializedProperty FindIdProperty(SerializedProperty property) {
|
||||
var prop = property.FindPropertyRelative("id");
|
||||
if(prop != null) {
|
||||
return prop;
|
||||
}
|
||||
return property.FindPropertyRelative("<id>k__BackingField");
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Editor/PopupElementTypeDrawer.cs.meta
Normal file
2
Editor/PopupElementTypeDrawer.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ea57be8755c60e4bbf156ac2b32c98c
|
||||
80
Editor/PopupSettingsProvider.cs
Normal file
80
Editor/PopupSettingsProvider.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem.Editor {
|
||||
public sealed class PopupSettingsProvider : SettingsProvider {
|
||||
private PopupSettings settings;
|
||||
|
||||
private PopupSettingsProvider(string path, SettingsScope scope)
|
||||
: base(path, scope) { }
|
||||
|
||||
private SerializedObject serializedSettings;
|
||||
|
||||
public override void OnActivate(string searchContext, UnityEngine.UIElements.VisualElement rootElement) {
|
||||
var guids = AssetDatabase.FindAssets("t:PopupSettings");
|
||||
if(guids.Length > 0) {
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||
settings = AssetDatabase.LoadAssetAtPath<PopupSettings>(path);
|
||||
}
|
||||
if(settings != null) {
|
||||
serializedSettings = new SerializedObject(settings);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext) {
|
||||
if(settings == null) {
|
||||
EditorGUILayout.HelpBox("No PopupSettings asset found. Create one via Assets > Create > Jovian > Popup System > Popup Settings.", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(10);
|
||||
EditorGUILayout.LabelField("Popup System Settings", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space(5);
|
||||
|
||||
serializedSettings.Update();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("popupDelay"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("fadeDuration"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("defaultAnchorSide"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("screenEdgePadding"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("maxPopupWidth"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("sortingOrder"));
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Follow Mouse", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("followMouseOffset"));
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Input", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("touchHoldDuration"));
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("gamepadFocusTrigger"));
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Element Prefabs", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("elementPrefabs"), true);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Priority", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("categoryPriorities"), true);
|
||||
|
||||
EditorGUILayout.Space(5);
|
||||
EditorGUILayout.LabelField("Per-Category Overrides", EditorStyles.boldLabel);
|
||||
EditorGUILayout.PropertyField(serializedSettings.FindProperty("categoryDelayOverrides"), true);
|
||||
|
||||
if(EditorGUI.EndChangeCheck()) {
|
||||
serializedSettings.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(settings);
|
||||
}
|
||||
}
|
||||
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateProvider() {
|
||||
var provider = new PopupSettingsProvider("Project/Jovian/Popup System", SettingsScope.Project) {
|
||||
keywords = new HashSet<string>(new[] { "popup", "tooltip", "hover", "delay" })
|
||||
};
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Editor/PopupSettingsProvider.cs.meta
Normal file
2
Editor/PopupSettingsProvider.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63a03b88ed78a934094ce61f9d127ec9
|
||||
343
README.md
343
README.md
@@ -1,3 +1,344 @@
|
||||
# unity-popup-system
|
||||
# Jovian Popup System
|
||||
|
||||
A lightweight, low-allocation popup and tooltip system for Unity with category-based isolation, a generic element cache, type-safe element identifiers, and extensible animations.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Unity 2022.3 or later
|
||||
- TextMeshPro 3.0.6+
|
||||
- Input System 1.18.0+
|
||||
- Newtonsoft JSON 3.2.1+
|
||||
|
||||
Install via the Unity Package Manager by adding the package from its local path or from a git URL.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create a PopupSettings asset
|
||||
|
||||
In the Unity Editor, go to **Assets > Create > Jovian > Popup System > Popup Settings**. Configure element prefabs by adding entries to the Element Prefabs list, mapping `PopupElementType` values to your prefabs.
|
||||
|
||||
### 2. Build a PopupReference prefab
|
||||
|
||||
See the [Prefab Setup](#prefab-setup) section below.
|
||||
|
||||
### 3. Create and use PopupSystem
|
||||
|
||||
```csharp
|
||||
using Jovian.PopupSystem;
|
||||
using Jovian.PopupSystem.UI;
|
||||
|
||||
// Create the system. canvasRoot auto-scans all PopupTrigger components.
|
||||
var popup = new PopupSystem(settings, viewPrefab, canvasRoot);
|
||||
|
||||
popup.RegisterCategory(PopupCategory.Item);
|
||||
popup.RegisterCategory(PopupCategory.Character);
|
||||
|
||||
// Set content on auto-scanned triggers by name.
|
||||
var handler = popup.GetTriggerHandler("ItemSlot");
|
||||
handler?.SetContent(builder => {
|
||||
builder
|
||||
.AddText("Health Potion", PopupElementType.Header)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddText("Restores health.", PopupElementType.Text)
|
||||
.AddNameValue("Heal Amount", 50, PopupElementType.LabelValueText);
|
||||
});
|
||||
|
||||
// Or show a popup directly from code.
|
||||
popup.Show(PopupCategory.Item, builder => {
|
||||
builder
|
||||
.AddText("Iron Sword", PopupElementType.Header)
|
||||
.AddNameValue("Damage", 12, PopupElementType.LabelValueText);
|
||||
}, anchorRect, AnchorSide.Right);
|
||||
|
||||
// Tick each frame.
|
||||
popup.Tick(Time.deltaTime);
|
||||
|
||||
// Clean up when the game state exits.
|
||||
popup.Dispose();
|
||||
```
|
||||
|
||||
## PopupElementType
|
||||
|
||||
`PopupElementType` is a type-safe struct identifying element prefabs in the registry. The Inspector shows a dropdown with built-in types plus a custom text field for game-specific elements.
|
||||
|
||||
### Built-in types
|
||||
|
||||
| Static Field | ID | Usage |
|
||||
|---|---|---|
|
||||
| `PopupElementType.Header` | `"header"` | Bold header text |
|
||||
| `PopupElementType.Text` | `"text"` | Body text |
|
||||
| `PopupElementType.LabelValueText` | `"label_value_text"` | Label + value row (two TMP_Text children) |
|
||||
| `PopupElementType.Image` | `"image"` | Image/icon element |
|
||||
| `PopupElementType.Separator` | `"separator"` | Horizontal divider line |
|
||||
|
||||
### Custom types
|
||||
|
||||
Define game-specific element types as static fields:
|
||||
|
||||
```csharp
|
||||
public static class MyPopupElements {
|
||||
public static readonly PopupElementType Badge = new("badge");
|
||||
public static readonly PopupElementType ProgressBar = new("progress_bar");
|
||||
}
|
||||
```
|
||||
|
||||
### Variants
|
||||
|
||||
Create variants of built-in types using `Variant()`:
|
||||
|
||||
```csharp
|
||||
// "header_gold" — a gold-styled header
|
||||
PopupElementType.Header.Variant("gold")
|
||||
|
||||
// "separator_thick" — a thicker separator
|
||||
PopupElementType.Separator.Variant("thick")
|
||||
```
|
||||
|
||||
Register variant prefabs in PopupSettings with the variant ID (e.g. "header_gold").
|
||||
|
||||
## PopupCategory
|
||||
|
||||
`PopupCategory` is a readonly struct that acts as a channel for isolating popups. Each category gets its own view instance.
|
||||
|
||||
### Built-in categories
|
||||
|
||||
```csharp
|
||||
PopupCategory.Character // Character tooltips
|
||||
PopupCategory.Item // Item tooltips
|
||||
PopupCategory.Skill // Skill tooltips
|
||||
PopupCategory.General // General-purpose tooltips
|
||||
```
|
||||
|
||||
### Custom categories
|
||||
|
||||
```csharp
|
||||
var lootCategory = new PopupCategory("Loot");
|
||||
popup.RegisterCategory(lootCategory, priority: 5);
|
||||
```
|
||||
|
||||
## PopupSettings
|
||||
|
||||
ScriptableObject holding all configuration. Create via **Assets > Create > Jovian > Popup System > Popup Settings**.
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|---|---|---|---|
|
||||
| `popupDelay` | float | 0.4 | Seconds before popup appears. |
|
||||
| `fadeDuration` | float | 0.2 | Fade animation duration. |
|
||||
| `defaultAnchorSide` | AnchorSide | Below | Default anchor side. |
|
||||
| `screenEdgePadding` | float | 10 | Minimum pixels from screen edge. |
|
||||
| `maxPopupWidth` | float | 400 | Maximum popup width in pixels. |
|
||||
| `sortingOrder` | int | 100 | Canvas sorting order. |
|
||||
| `followMouseOffset` | Vector2 | (15, -15) | Cursor offset in follow mode. |
|
||||
| `touchHoldDuration` | float | 0.6 | Touch hold duration. |
|
||||
| `gamepadFocusTrigger` | bool | true | Trigger on gamepad focus. |
|
||||
| `elementPrefabs` | List | empty | Element prefab registry (PopupElementType -> prefab). |
|
||||
| `categoryPriorities` | List | empty | Per-category priority overrides. |
|
||||
| `categoryDelayOverrides` | List | empty | Per-category delay overrides. |
|
||||
|
||||
## PopupContentBuilder
|
||||
|
||||
Fluent API struct for composing popup content. All methods take a `PopupElementType` to identify which prefab to use.
|
||||
|
||||
### Methods
|
||||
|
||||
```csharp
|
||||
// Generic — returns raw GameObject for custom elements
|
||||
builder.Add(PopupElementType.Header);
|
||||
builder.Add(new PopupElementType("custom_widget"));
|
||||
|
||||
// Text — sets TMP_Text on the element
|
||||
builder.AddText("Fireball", PopupElementType.Header);
|
||||
builder.AddText("Body text here.", PopupElementType.Text);
|
||||
builder.AddText("Colored text", "#FFD700", PopupElementType.Text);
|
||||
|
||||
// Name/Value — sets two TMP_Text children (label + value)
|
||||
builder.AddNameValue("Damage", 120, PopupElementType.LabelValueText);
|
||||
builder.AddNameValue("Range", "15m", PopupElementType.LabelValueText);
|
||||
|
||||
// Image — sets sprite and height
|
||||
builder.AddImage(iconSprite, PopupElementType.Image, 64f);
|
||||
|
||||
// Separator
|
||||
builder.AddSeparator(PopupElementType.Separator);
|
||||
```
|
||||
|
||||
### Full example
|
||||
|
||||
```csharp
|
||||
popup.Show(PopupCategory.Skill, builder => {
|
||||
builder
|
||||
.AddText("Fireball", PopupElementType.Header)
|
||||
.AddText("Hurls a ball of fire.", PopupElementType.Text)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddNameValue("Damage", 120, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Mana Cost", 35, PopupElementType.LabelValueText)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddText("Requires: Level 5", "FF6666", PopupElementType.Text);
|
||||
}, targetRect);
|
||||
```
|
||||
|
||||
## PopupTrigger
|
||||
|
||||
MonoBehaviour attached to UI elements for hover-based popups. Forwards pointer events to a `PopupTriggerView` behavior handler.
|
||||
|
||||
### Inspector fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|---|---|---|
|
||||
| `category` | PopupCategory | Which category channel to use. |
|
||||
| `anchorSide` | AnchorSide | Which side to anchor the popup. |
|
||||
| `positionMode` | PopupPositionMode | `AnchorToElement` or `FollowMouse`. |
|
||||
|
||||
### Approach 1: Auto-scanned triggers (recommended for static UI)
|
||||
|
||||
```csharp
|
||||
var popup = new PopupSystem(settings, viewPrefab, canvasRoot);
|
||||
popup.RegisterCategory(PopupCategory.Character);
|
||||
|
||||
// GetTriggerHandler returns PopupTriggerView (the behavior handler)
|
||||
var handler = popup.GetTriggerHandler("HeroPortrait");
|
||||
handler?.SetContent(builder => {
|
||||
builder
|
||||
.AddText("Kael", PopupElementType.Header)
|
||||
.AddNameValue("Health", 55, PopupElementType.LabelValueText);
|
||||
});
|
||||
|
||||
// Or all handlers for a category
|
||||
foreach(var h in popup.GetTriggerHandlers(PopupCategory.Item)) {
|
||||
h.SetContent(builder => builder.AddText("Item", PopupElementType.Header));
|
||||
}
|
||||
```
|
||||
|
||||
### Approach 2: Dynamic triggers (for runtime-created UI)
|
||||
|
||||
```csharp
|
||||
popup.InitializeTriggersInChildren(slotsContainer, (trigger, view) => {
|
||||
var slotData = trigger.GetComponentInParent<SlotComponent>();
|
||||
view.SetContent(builder => {
|
||||
builder.AddText(slotData.itemName, PopupElementType.Header);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Approach 3: Code-only (no PopupTrigger needed)
|
||||
|
||||
```csharp
|
||||
// Anchored
|
||||
popupSystem.Show(PopupCategory.Item, builder => { ... }, targetRect, AnchorSide.Right);
|
||||
|
||||
// Follow mouse
|
||||
popupSystem.Show(PopupCategory.General, builder => { ... });
|
||||
|
||||
// Fixed screen position
|
||||
popupSystem.ShowAtPosition(PopupCategory.General, builder => { ... }, screenPos);
|
||||
|
||||
// Hide
|
||||
popupSystem.Hide(PopupCategory.Item);
|
||||
popupSystem.HideAll();
|
||||
```
|
||||
|
||||
## Priority System
|
||||
|
||||
Higher priority categories dismiss lower ones when shown:
|
||||
|
||||
```csharp
|
||||
popup.RegisterCategory(PopupCategory.Character, priority: 10);
|
||||
popup.RegisterCategory(PopupCategory.Item, priority: 5);
|
||||
```
|
||||
|
||||
Settings-based priorities take precedence over registration arguments.
|
||||
|
||||
## Lifecycle Integration
|
||||
|
||||
Created per game state, not as a singleton:
|
||||
|
||||
```csharp
|
||||
var guiCanvas = guiReferences.GetComponentInParent<Canvas>().transform;
|
||||
var popupSystem = new PopupSystem(popupSettings, popupViewPrefab, guiCanvas);
|
||||
popupSystem.RegisterCategory(PopupCategory.Character, priority: 10);
|
||||
|
||||
// Tick each frame
|
||||
popupSystem.Tick(Time.deltaTime);
|
||||
|
||||
// Dispose on state exit
|
||||
popupSystem.Dispose();
|
||||
```
|
||||
|
||||
## IPopupAnimator
|
||||
|
||||
Extensible show/hide animation interface. Default: `FadePopupAnimator` (alpha lerp). Pass a factory to the constructor:
|
||||
|
||||
```csharp
|
||||
var popup = new PopupSystem(settings, viewPrefab, canvasRoot, () => new ScalePopupAnimator());
|
||||
```
|
||||
|
||||
## Prefab Setup
|
||||
|
||||
```
|
||||
PopupReferencePrefab Canvas, CanvasGroup, CanvasScaler, PopupReference
|
||||
Background Image, ContentSizeFitter (V=Preferred)
|
||||
Content VerticalLayoutGroup (Control Child Width, Force Expand Width)
|
||||
```
|
||||
|
||||
1. **Root**: Canvas (Screen Space Overlay), CanvasScaler (Scale With Screen Size), CanvasGroup, PopupReference. Point anchors, no ContentSizeFitter.
|
||||
2. **Background**: Image, ContentSizeFitter (Vertical = Preferred).
|
||||
3. **Content**: Stretched to Background, VerticalLayoutGroup (Control Child Size Width, Child Force Expand Width), no ContentSizeFitter.
|
||||
4. **Element prefabs**: Create separate prefabs, register in PopupSettings under Element Prefabs with their `PopupElementType`. No ContentSizeFitter on element prefabs.
|
||||
5. **Wire PopupReference**: Assign Content, CanvasGroup, and Background fields.
|
||||
|
||||
## Optimization Notes
|
||||
|
||||
- `PopupCategory` and `PopupElementType` are value-type structs — zero heap allocation
|
||||
- `PopupContentBuilder` is a readonly struct operating directly on cached elements
|
||||
- Content elements use a **grow-only cache** keyed by `PopupElementType` — activate/deactivate, never destroy after warmup
|
||||
- Delay timers and animation driven by float fields in `Tick()` — no coroutines
|
||||
- Screen rect uses static `Vector3[4]` buffer — no per-frame allocation
|
||||
- Layout rebuilds only on content change (dirty flag)
|
||||
- Each category gets its own `IPopupAnimator` — no concurrent animation corruption
|
||||
- MonoBehaviour (`PopupReference`, `PopupTrigger`) holds references only; all behavior in plain C# classes (`PopupView`, `PopupTriggerView`)
|
||||
|
||||
## Samples
|
||||
|
||||
The `Samples~` folder contains:
|
||||
|
||||
- **Prefabs**: PopupReferencePrefab and all element prefabs
|
||||
- **Settings**: Pre-configured PopupSettings asset
|
||||
- **Scripts**: Three example scripts (auto-scanned triggers, dynamic triggers, code-only with variants)
|
||||
|
||||
Import via Unity Package Manager: select the package, expand Samples, click Import.
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Types
|
||||
|
||||
| Type | Namespace | Description |
|
||||
|---|---|---|
|
||||
| `IPopupSystem` | `Jovian.PopupSystem` | Main interface for showing/hiding popups. |
|
||||
| `PopupSystem` | `Jovian.PopupSystem` | Implementation. Constructor: `(PopupSettings, PopupReference, Transform, Func<IPopupAnimator>)`. |
|
||||
| `PopupView` | `Jovian.PopupSystem` | Behavior class: generic element cache, positioning, visibility. |
|
||||
| `PopupSettings` | `Jovian.PopupSystem` | ScriptableObject configuration + element prefab registry. |
|
||||
| `PopupCategory` | `Jovian.PopupSystem` | Struct identifying a popup channel. |
|
||||
| `PopupElementType` | `Jovian.PopupSystem` | Struct identifying an element prefab type. Built-ins + Variant(). |
|
||||
| `PopupContentBuilder` | `Jovian.PopupSystem` | Fluent readonly struct for building content. |
|
||||
|
||||
### UI Types
|
||||
|
||||
| Type | Namespace | Description |
|
||||
|---|---|---|
|
||||
| `PopupReference` | `Jovian.PopupSystem.UI` | MonoBehaviour reference holder (content, canvasGroup, background). |
|
||||
| `PopupTrigger` | `Jovian.PopupSystem.UI` | MonoBehaviour reference holder for hover triggers. |
|
||||
| `PopupTriggerView` | `Jovian.PopupSystem` | Behavior handler for triggers (SetContent, pointer forwarding). |
|
||||
|
||||
### Animation Types
|
||||
|
||||
| Type | Namespace | Description |
|
||||
|---|---|---|
|
||||
| `IPopupAnimator` | `Jovian.PopupSystem` | Interface for custom show/hide animations. |
|
||||
| `FadePopupAnimator` | `Jovian.PopupSystem` | Default fade animation via CanvasGroup alpha. |
|
||||
|
||||
### Enums
|
||||
|
||||
| Type | Values |
|
||||
|---|---|
|
||||
| `AnchorSide` | `Below`, `Above`, `Left`, `Right` |
|
||||
| `PopupPositionMode` | `AnchorToElement`, `FollowMouse` |
|
||||
|
||||
7
README.md.meta
Normal file
7
README.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d33518dac7899604c9ceeda21897315d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Runtime.meta
Normal file
8
Runtime.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05f691cbfb7413f4fb735b2ec732ff06
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
56
Runtime/FadePopupAnimator.cs
Normal file
56
Runtime/FadePopupAnimator.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Default popup animator that fades CanvasGroup alpha. Each category gets its own instance
|
||||
/// so concurrent show/hide animations don't corrupt each other.
|
||||
/// </summary>
|
||||
public sealed class FadePopupAnimator : IPopupAnimator {
|
||||
private CanvasGroup target;
|
||||
private float timer;
|
||||
private float elapsed;
|
||||
private float startAlpha;
|
||||
private float endAlpha;
|
||||
private Action onFinish;
|
||||
|
||||
public bool IsAnimating => target != null;
|
||||
|
||||
public void Show(CanvasGroup canvasGroup, float duration, Action onComplete) {
|
||||
target = canvasGroup;
|
||||
timer = Mathf.Max(duration, 0.001f);
|
||||
elapsed = 0f;
|
||||
startAlpha = 0f;
|
||||
endAlpha = 1f;
|
||||
onFinish = onComplete;
|
||||
canvasGroup.alpha = 0f;
|
||||
}
|
||||
|
||||
public void Hide(CanvasGroup canvasGroup, float duration, Action onComplete) {
|
||||
target = canvasGroup;
|
||||
timer = Mathf.Max(duration, 0.001f);
|
||||
elapsed = 0f;
|
||||
startAlpha = canvasGroup.alpha;
|
||||
endAlpha = 0f;
|
||||
onFinish = onComplete;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime) {
|
||||
if(target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
elapsed += deltaTime;
|
||||
var t = Mathf.Clamp01(elapsed / timer);
|
||||
target.alpha = Mathf.Lerp(startAlpha, endAlpha, t);
|
||||
|
||||
if(!(t >= 1f)) {
|
||||
return;
|
||||
}
|
||||
var callback = onFinish;
|
||||
target = null;
|
||||
onFinish = null;
|
||||
callback?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/FadePopupAnimator.cs.meta
Normal file
2
Runtime/FadePopupAnimator.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 254bb620ce056dd41905258eb0f070d7
|
||||
37
Runtime/IPopupAnimator.cs
Normal file
37
Runtime/IPopupAnimator.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Interface for popup show/hide animations. Each registered category gets its own instance
|
||||
/// to prevent state corruption during concurrent animations. Driven by float timers in
|
||||
/// <see cref="Tick"/>, not coroutines.
|
||||
/// </summary>
|
||||
public interface IPopupAnimator {
|
||||
/// <summary>
|
||||
/// Begins a show animation on the given CanvasGroup. Typically fades alpha from 0 to 1.
|
||||
/// </summary>
|
||||
/// <param name="canvasGroup">The CanvasGroup to animate.</param>
|
||||
/// <param name="duration">Animation duration in seconds.</param>
|
||||
/// <param name="onComplete">Callback invoked when the animation finishes. May be null.</param>
|
||||
void Show(CanvasGroup canvasGroup, float duration, Action onComplete);
|
||||
|
||||
/// <summary>
|
||||
/// Begins a hide animation on the given CanvasGroup. Typically fades alpha to 0.
|
||||
/// </summary>
|
||||
/// <param name="canvasGroup">The CanvasGroup to animate.</param>
|
||||
/// <param name="duration">Animation duration in seconds.</param>
|
||||
/// <param name="onComplete">Callback invoked when the animation finishes. May be null.</param>
|
||||
void Hide(CanvasGroup canvasGroup, float duration, Action onComplete);
|
||||
|
||||
/// <summary>
|
||||
/// Advances the animation by deltaTime. Call every frame from <see cref="IPopupSystem.Tick"/>.
|
||||
/// </summary>
|
||||
void Tick(float deltaTime);
|
||||
|
||||
/// <summary>
|
||||
/// True if an animation is currently in progress.
|
||||
/// </summary>
|
||||
bool IsAnimating { get; }
|
||||
}
|
||||
}
|
||||
2
Runtime/IPopupAnimator.cs.meta
Normal file
2
Runtime/IPopupAnimator.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b146d885db3dcef4fa70abd3f43683d3
|
||||
79
Runtime/IPopupSystem.cs
Normal file
79
Runtime/IPopupSystem.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Core interface for the popup system. Created per game state, not as a singleton.
|
||||
/// Manages category registration, trigger discovery, popup display, and lifecycle.
|
||||
/// </summary>
|
||||
public interface IPopupSystem {
|
||||
/// <summary>
|
||||
/// Scans all <see cref="PopupTrigger"/> components under the given parent and binds them
|
||||
/// to this system. Each trigger receives a <see cref="PopupTriggerView"/> for behavior.
|
||||
/// </summary>
|
||||
void ScanTriggers(Transform parent);
|
||||
|
||||
/// <summary>
|
||||
/// Scans all <see cref="PopupTrigger"/> components under the given parent, binds them,
|
||||
/// and invokes the configure callback with both the trigger (for hierarchy queries) and
|
||||
/// its view (for setting content).
|
||||
/// </summary>
|
||||
void InitializeTriggersInChildren(Transform parent, Action<PopupTrigger, PopupTriggerView> configureTrigger);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="PopupTriggerView"/> for the first registered trigger whose
|
||||
/// GameObject name matches. Returns null if not found.
|
||||
/// </summary>
|
||||
PopupTriggerView GetTriggerHandler(string gameObjectName);
|
||||
|
||||
/// <summary>
|
||||
/// Returns all <see cref="PopupTriggerView"/> instances registered under the given category.
|
||||
/// </summary>
|
||||
IReadOnlyList<PopupTriggerView> GetTriggerHandlers(PopupCategory category);
|
||||
|
||||
/// <summary>
|
||||
/// Registers a popup category. Each category gets its own <see cref="PopupReference"/> instance
|
||||
/// (lazily created on first show) and its own <see cref="IPopupAnimator"/>.
|
||||
/// </summary>
|
||||
/// <param name="category">The category to register.</param>
|
||||
/// <param name="priority">Fallback priority if not defined in <see cref="PopupSettings"/>. Higher dismisses lower.</param>
|
||||
void RegisterCategory(PopupCategory category, int priority = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a popup for the given category after the configured delay. The build callback
|
||||
/// populates content via <see cref="PopupContentBuilder"/>. Optionally anchors to a
|
||||
/// RectTransform or follows the mouse if no anchor is provided.
|
||||
/// </summary>
|
||||
void Show(PopupCategory category, Action<PopupContentBuilder> buildContent,
|
||||
RectTransform anchor = null, AnchorSide? anchorSide = null);
|
||||
|
||||
/// <summary>
|
||||
/// Shows a popup for the given category at a fixed screen position.
|
||||
/// </summary>
|
||||
void ShowAtPosition(PopupCategory category, Action<PopupContentBuilder> buildContent,
|
||||
Vector2 screenPosition);
|
||||
|
||||
/// <summary>
|
||||
/// Hides the popup for the given category with a fade-out animation.
|
||||
/// </summary>
|
||||
void Hide(PopupCategory category);
|
||||
|
||||
/// <summary>
|
||||
/// Hides all visible popups across all categories.
|
||||
/// </summary>
|
||||
void HideAll();
|
||||
|
||||
/// <summary>
|
||||
/// Drives delay timers, animations, and follow-mouse positioning. Call every frame.
|
||||
/// </summary>
|
||||
void Tick(float deltaTime);
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all popup view GameObjects and clears registered categories.
|
||||
/// Call when the owning game state exits.
|
||||
/// </summary>
|
||||
void Dispose();
|
||||
}
|
||||
}
|
||||
2
Runtime/IPopupSystem.cs.meta
Normal file
2
Runtime/IPopupSystem.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65d563f87bb09de48b8edd12101cdd11
|
||||
19
Runtime/Jovian.PopupSystem.asmdef
Normal file
19
Runtime/Jovian.PopupSystem.asmdef
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "Jovian.PopupSystem",
|
||||
"rootNamespace": "Jovian.PopupSystem",
|
||||
"references": [
|
||||
"Unity.TextMeshPro",
|
||||
"Unity.InputSystem"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"Newtonsoft.Json.dll"
|
||||
],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Runtime/Jovian.PopupSystem.asmdef.meta
Normal file
7
Runtime/Jovian.PopupSystem.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31bcaef770c58d94db7f78106f15fd4e
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Runtime/PopupCategory.cs
Normal file
48
Runtime/PopupCategory.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Value type identifying a popup channel. Each category gets its own popup view instance.
|
||||
/// Compared by string ID using ordinal comparison. Define custom categories as static fields.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct PopupCategory : IEquatable<PopupCategory> {
|
||||
[SerializeField] string id;
|
||||
|
||||
public string Id => id;
|
||||
|
||||
public PopupCategory(string id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static readonly PopupCategory Character = new("Character");
|
||||
public static readonly PopupCategory Item = new("Item");
|
||||
public static readonly PopupCategory Skill = new("Skill");
|
||||
public static readonly PopupCategory General = new("General");
|
||||
|
||||
public bool Equals(PopupCategory other) {
|
||||
return string.Equals(id, other.id, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return obj is PopupCategory other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return id != null ? id.GetHashCode() : 0;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return id ?? string.Empty;
|
||||
}
|
||||
|
||||
public static bool operator ==(PopupCategory left, PopupCategory right) {
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PopupCategory left, PopupCategory right) {
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupCategory.cs.meta
Normal file
2
Runtime/PopupCategory.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcd1fb0ef93fed0489a43977bc71594b
|
||||
15
Runtime/PopupCategoryJsonConverter.cs
Normal file
15
Runtime/PopupCategoryJsonConverter.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
public sealed class PopupCategoryJsonConverter : JsonConverter<PopupCategory> {
|
||||
public override void WriteJson(JsonWriter writer, PopupCategory value, JsonSerializer serializer) {
|
||||
writer.WriteValue(value.Id);
|
||||
}
|
||||
|
||||
public override PopupCategory ReadJson(JsonReader reader, Type objectType, PopupCategory existingValue, bool hasExistingValue, JsonSerializer serializer) {
|
||||
var id = reader.Value as string;
|
||||
return new PopupCategory(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupCategoryJsonConverter.cs.meta
Normal file
2
Runtime/PopupCategoryJsonConverter.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 683182ef8e2aa6b4daffc547c481b768
|
||||
115
Runtime/PopupContentBuilder.cs
Normal file
115
Runtime/PopupContentBuilder.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Fluent API struct for building popup content. Operates on the generic element cache
|
||||
/// inside a <see cref="PopupView"/>. Received in the build callback passed to
|
||||
/// <see cref="IPopupSystem.Show"/>. Use <see cref="Add"/> for fully custom elements,
|
||||
/// or convenience methods for common types.
|
||||
/// </summary>
|
||||
public readonly struct PopupContentBuilder {
|
||||
readonly PopupView view;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a builder targeting the given popup view.
|
||||
/// </summary>
|
||||
public PopupContentBuilder(PopupView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cached or newly instantiated element by its registered type.
|
||||
/// Use this for fully custom or game-specific element types.
|
||||
/// </summary>
|
||||
public GameObject Add(PopupElementType elementType) {
|
||||
return view.GetElement(elementType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a text element using the given element type and sets its TMP_Text content.
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddText(string text, PopupElementType elementType) {
|
||||
var go = view.GetElement(elementType);
|
||||
if(go == null) {
|
||||
return this;
|
||||
}
|
||||
var tmp = go.GetComponentInChildren<TMP_Text>();
|
||||
if(tmp) {
|
||||
tmp.text = text;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a colored text element using the given element type.
|
||||
/// Hex color can be with or without the # prefix.
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddText(string text, string hexColor, PopupElementType elementType) {
|
||||
var go = view.GetElement(elementType);
|
||||
if(!go) {
|
||||
return this;
|
||||
}
|
||||
var tmp = go.GetComponentInChildren<TMP_Text>();
|
||||
if(!tmp) {
|
||||
return this;
|
||||
}
|
||||
var prefix = hexColor.Length > 0 && hexColor[0] == '#' ? "" : "#";
|
||||
tmp.text = $"<color={prefix}{hexColor}>{text}</color>";
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a name/value row using the given element type. The prefab must have
|
||||
/// exactly two TMP_Text children (label first, value second).
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddNameValue(string label, int value, PopupElementType elementType) {
|
||||
return AddNameValueInternal(elementType, label, value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a name/value row using the given element type. The prefab must have
|
||||
/// exactly two TMP_Text children (label first, value second).
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddNameValue(string label, string value, PopupElementType elementType) {
|
||||
return AddNameValueInternal(elementType, label, value);
|
||||
}
|
||||
|
||||
private PopupContentBuilder AddNameValueInternal(PopupElementType elementType, string label, string value) {
|
||||
var go = view.GetElement(elementType);
|
||||
if(go != null) {
|
||||
var children = go.GetComponentsInChildren<TMP_Text>(true);
|
||||
if(children.Length >= 2) {
|
||||
children[0].text = label;
|
||||
children[1].text = value;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an image element with the given sprite and optional height.
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddImage(Sprite sprite, PopupElementType elementType, float height = 64f) {
|
||||
var go = view.GetElement(elementType);
|
||||
if(go != null) {
|
||||
var image = go.GetComponentInChildren<Image>();
|
||||
if(image != null) {
|
||||
image.sprite = sprite;
|
||||
var rt = (RectTransform)image.transform;
|
||||
rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a separator element using the given element type.
|
||||
/// </summary>
|
||||
public PopupContentBuilder AddSeparator(PopupElementType elementType) {
|
||||
view.GetElement(elementType);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupContentBuilder.cs.meta
Normal file
2
Runtime/PopupContentBuilder.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9f4094c471d0464e95e330331acc813
|
||||
74
Runtime/PopupElementType.cs
Normal file
74
Runtime/PopupElementType.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Value type identifying a popup element prefab. Compared by string ID using ordinal
|
||||
/// comparison. Built-in types cover common popup elements. Define custom types as static
|
||||
/// fields or create instances for game-specific elements and variants.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct PopupElementType : IEquatable<PopupElementType> {
|
||||
[SerializeField] private string id;
|
||||
|
||||
/// <summary>The string identifier for this element type.</summary>
|
||||
public string Id => id;
|
||||
|
||||
public PopupElementType(string id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// --- Built-in types ---
|
||||
|
||||
/// <summary>Bold header text element.</summary>
|
||||
public static readonly PopupElementType Header = new("header");
|
||||
|
||||
/// <summary>Body text element.</summary>
|
||||
public static readonly PopupElementType Text = new("text");
|
||||
|
||||
/// <summary>Label + value stat row element.</summary>
|
||||
public static readonly PopupElementType LabelValueText = new("label_value_text");
|
||||
|
||||
/// <summary>Image/icon element.</summary>
|
||||
public static readonly PopupElementType Image = new("image");
|
||||
|
||||
/// <summary>Horizontal separator line.</summary>
|
||||
public static readonly PopupElementType Separator = new("separator");
|
||||
|
||||
// --- Variant helper ---
|
||||
|
||||
/// <summary>
|
||||
/// Creates a variant of this element type by appending a suffix.
|
||||
/// e.g. <c>PopupElementType.Header.Variant("gold")</c> produces <c>"header_gold"</c>.
|
||||
/// </summary>
|
||||
public PopupElementType Variant(string variant) {
|
||||
return new PopupElementType($"{id}_{variant}");
|
||||
}
|
||||
|
||||
// --- Equality ---
|
||||
|
||||
public bool Equals(PopupElementType other) {
|
||||
return string.Equals(id, other.id, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) {
|
||||
return obj is PopupElementType other && Equals(other);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return id != null ? id.GetHashCode() : 0;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return id ?? string.Empty;
|
||||
}
|
||||
|
||||
public static bool operator ==(PopupElementType left, PopupElementType right) {
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(PopupElementType left, PopupElementType right) {
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupElementType.cs.meta
Normal file
2
Runtime/PopupElementType.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ba7e78e3d930334a935a600a8f67ded
|
||||
13
Runtime/PopupEnums.cs
Normal file
13
Runtime/PopupEnums.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Jovian.PopupSystem {
|
||||
public enum AnchorSide {
|
||||
Below,
|
||||
Above,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
public enum PopupPositionMode {
|
||||
AnchorToElement,
|
||||
FollowMouse
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupEnums.cs.meta
Normal file
2
Runtime/PopupEnums.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01e69680e496eca4daebbc1874e3a7d9
|
||||
96
Runtime/PopupSettings.cs
Normal file
96
Runtime/PopupSettings.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// ScriptableObject holding all popup system configuration. Create via
|
||||
/// Assets > Create > Jovian > Popup System > Popup Settings.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "PopupSettings", menuName = "Jovian/Popup System/Popup Settings")]
|
||||
public class PopupSettings : ScriptableObject {
|
||||
[Header("General")]
|
||||
public float popupDelay = 0.4f;
|
||||
public float fadeDuration = 0.2f;
|
||||
public AnchorSide defaultAnchorSide = AnchorSide.Below;
|
||||
public float screenEdgePadding = 10f;
|
||||
public float maxPopupWidth = 400f;
|
||||
public int sortingOrder = 100;
|
||||
|
||||
[Header("Follow Mouse")]
|
||||
public Vector2 followMouseOffset = new(15f, -15f);
|
||||
|
||||
[Header("Input")]
|
||||
public float touchHoldDuration = 0.6f;
|
||||
public bool gamepadFocusTrigger = true;
|
||||
|
||||
[Header("Element Prefabs")]
|
||||
public List<PopupElementEntry> elementPrefabs = new();
|
||||
|
||||
[Header("Priority")]
|
||||
public List<CategoryPriority> categoryPriorities = new();
|
||||
|
||||
[Header("Per-Category Overrides")]
|
||||
public List<CategoryDelay> categoryDelayOverrides = new();
|
||||
|
||||
private Dictionary<PopupElementType, GameObject> prefabLookup;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the element prefab registered under the given type, or null if not found.
|
||||
/// </summary>
|
||||
public GameObject GetPrefab(PopupElementType elementType) {
|
||||
if(prefabLookup == null) {
|
||||
prefabLookup = new Dictionary<PopupElementType, GameObject>();
|
||||
foreach(var entry in elementPrefabs) {
|
||||
if(!string.IsNullOrEmpty(entry.type.Id) && entry.prefab != null) {
|
||||
prefabLookup[entry.type] = entry.prefab;
|
||||
}
|
||||
}
|
||||
}
|
||||
prefabLookup.TryGetValue(elementType, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the configured priority for a category, or 0 if not configured.
|
||||
/// </summary>
|
||||
public int GetPriority(PopupCategory category) {
|
||||
foreach(var cp in categoryPriorities) {
|
||||
if(cp.category == category) {
|
||||
return cp.priority;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the configured delay override for a category, or the default popupDelay.
|
||||
/// </summary>
|
||||
public float GetDelay(PopupCategory category) {
|
||||
foreach(var cd in categoryDelayOverrides) {
|
||||
if(cd.category == category) {
|
||||
return cd.delay;
|
||||
}
|
||||
}
|
||||
return popupDelay;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class PopupElementEntry {
|
||||
public PopupElementType type;
|
||||
public GameObject prefab;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class CategoryPriority {
|
||||
public PopupCategory category;
|
||||
public int priority;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class CategoryDelay {
|
||||
public PopupCategory category;
|
||||
public float delay;
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupSettings.cs.meta
Normal file
2
Runtime/PopupSettings.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e38e313f3665d464b82b22699b2a4634
|
||||
282
Runtime/PopupSystem.cs
Normal file
282
Runtime/PopupSystem.cs
Normal file
@@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Core implementation of <see cref="IPopupSystem"/>. Created per game state, not as a singleton.
|
||||
/// Manages category registration, trigger discovery, popup lifecycle, priority dismissal, and
|
||||
/// tick-driven delay timers and animations. Pass a canvasParent to auto-scan triggers on construction.
|
||||
/// </summary>
|
||||
public sealed class PopupSystem : IPopupSystem {
|
||||
readonly PopupSettings settings;
|
||||
readonly PopupReference viewPrefab;
|
||||
readonly Func<IPopupAnimator> animatorFactory;
|
||||
readonly Transform canvasParent;
|
||||
readonly Dictionary<PopupCategory, ViewState> categories = new();
|
||||
readonly List<PopupTrigger> registeredTriggers = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new popup system instance.
|
||||
/// </summary>
|
||||
/// <param name="settings">Configuration ScriptableObject with delays, priorities, and display settings.</param>
|
||||
/// <param name="viewPrefab">The PopupReference prefab to instantiate per category.</param>
|
||||
/// <param name="canvasParent">Optional parent Canvas transform. When provided, popup views are parented
|
||||
/// here (inheriting CanvasScaler) and all PopupTrigger components are auto-scanned.</param>
|
||||
/// <param name="animatorFactory">Optional factory for custom animators. Defaults to FadePopupAnimator.</param>
|
||||
public PopupSystem(PopupSettings settings, PopupReference viewPrefab, Transform canvasParent = null, Func<IPopupAnimator> animatorFactory = null) {
|
||||
this.settings = settings;
|
||||
this.viewPrefab = viewPrefab;
|
||||
this.canvasParent = canvasParent;
|
||||
this.animatorFactory = animatorFactory ?? (() => new FadePopupAnimator());
|
||||
|
||||
// Auto-scan if a parent was provided
|
||||
if(canvasParent != null) {
|
||||
ScanTriggers(canvasParent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void RegisterCategory(PopupCategory category, int priority = 0) {
|
||||
if(categories.ContainsKey(category)) {
|
||||
return;
|
||||
}
|
||||
var effectivePriority = settings.GetPriority(category);
|
||||
if(effectivePriority == 0) {
|
||||
effectivePriority = priority;
|
||||
}
|
||||
categories[category] = new ViewState {
|
||||
priority = effectivePriority,
|
||||
delay = settings.GetDelay(category),
|
||||
animator = animatorFactory()
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Show(PopupCategory category, Action<PopupContentBuilder> buildContent,
|
||||
RectTransform anchor = null, AnchorSide? anchorSide = null) {
|
||||
if(!categories.TryGetValue(category, out var state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DismissLowerPriority(state.priority);
|
||||
|
||||
state.pendingBuild = buildContent;
|
||||
state.pendingAnchor = anchor;
|
||||
state.pendingAnchorSide = anchorSide ?? settings.defaultAnchorSide;
|
||||
state.pendingScreenPos = null;
|
||||
state.delayTimer = state.delay;
|
||||
state.isPending = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ShowAtPosition(PopupCategory category, Action<PopupContentBuilder> buildContent,
|
||||
Vector2 screenPosition) {
|
||||
if(!categories.TryGetValue(category, out var state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DismissLowerPriority(state.priority);
|
||||
|
||||
state.pendingBuild = buildContent;
|
||||
state.pendingAnchor = null;
|
||||
state.pendingScreenPos = screenPosition;
|
||||
state.delayTimer = state.delay;
|
||||
state.isPending = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Hide(PopupCategory category) {
|
||||
if(!categories.TryGetValue(category, out var state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.isPending = false;
|
||||
if(state.view != null && state.view.IsVisible) {
|
||||
state.animator.Hide(state.view.CanvasGroup, settings.fadeDuration, () => {
|
||||
state.view.SetVisible(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void HideAll() {
|
||||
foreach(var kvp in categories) {
|
||||
Hide(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Tick(float deltaTime) {
|
||||
foreach(var kvp in categories) {
|
||||
kvp.Value.animator.Tick(deltaTime);
|
||||
}
|
||||
|
||||
foreach(var kvp in categories) {
|
||||
var state = kvp.Value;
|
||||
if(!state.isPending) {
|
||||
continue;
|
||||
}
|
||||
|
||||
state.delayTimer -= deltaTime;
|
||||
if(state.delayTimer > 0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
state.isPending = false;
|
||||
ShowImmediate(state);
|
||||
}
|
||||
|
||||
foreach(var kvp in categories) {
|
||||
var state = kvp.Value;
|
||||
if(state.view != null && state.view.IsVisible && state.isFollowMouse) {
|
||||
state.view.UpdatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ScanTriggers(Transform parent) {
|
||||
var triggers = parent.GetComponentsInChildren<PopupTrigger>(true);
|
||||
foreach(var trigger in triggers) {
|
||||
if(!registeredTriggers.Contains(trigger)) {
|
||||
BindTrigger(trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public PopupTriggerView GetTriggerHandler(string gameObjectName) {
|
||||
foreach(var trigger in registeredTriggers) {
|
||||
if(trigger != null && trigger.gameObject.name == gameObjectName) {
|
||||
return trigger.Handler;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<PopupTriggerView> GetTriggerHandlers(PopupCategory category) {
|
||||
var result = new List<PopupTriggerView>();
|
||||
foreach(var trigger in registeredTriggers) {
|
||||
if(trigger != null && trigger.Category == category && trigger.Handler != null) {
|
||||
result.Add(trigger.Handler);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void InitializeTriggersInChildren(Transform parent, Action<PopupTrigger, PopupTriggerView> configureTrigger) {
|
||||
var triggers = parent.GetComponentsInChildren<PopupTrigger>(true);
|
||||
foreach(var trigger in triggers) {
|
||||
if(!registeredTriggers.Contains(trigger)) {
|
||||
BindTrigger(trigger);
|
||||
}
|
||||
configureTrigger(trigger, trigger.Handler);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindTrigger(PopupTrigger trigger) {
|
||||
var handler = new PopupTriggerView(this);
|
||||
trigger.Bind(handler);
|
||||
registeredTriggers.Add(trigger);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() {
|
||||
foreach(var kvp in categories) {
|
||||
if(kvp.Value.view?.Reference != null) {
|
||||
Object.Destroy(kvp.Value.view.Reference.gameObject);
|
||||
}
|
||||
}
|
||||
categories.Clear();
|
||||
}
|
||||
|
||||
private void ShowImmediate(ViewState state) {
|
||||
EnsureView(state);
|
||||
state.view.ClearContent();
|
||||
|
||||
var builder = new PopupContentBuilder(state.view);
|
||||
state.pendingBuild?.Invoke(builder);
|
||||
|
||||
// Activate before layout rebuild so Unity has an active hierarchy to calculate
|
||||
state.view.CanvasGroup.alpha = 0f;
|
||||
state.view.SetVisible(true);
|
||||
|
||||
// Force full layout rebuild so positioning has correct size on first show
|
||||
Canvas.ForceUpdateCanvases();
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(state.view.Content);
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)state.view.Transform);
|
||||
|
||||
if(state.pendingScreenPos.HasValue) {
|
||||
state.view.SetFixedPosition(state.pendingScreenPos.Value, settings.screenEdgePadding);
|
||||
state.isFollowMouse = false;
|
||||
}
|
||||
else if(state.pendingAnchor != null) {
|
||||
state.view.SetAnchorMode(state.pendingAnchor, state.pendingAnchorSide, settings.screenEdgePadding);
|
||||
state.isFollowMouse = false;
|
||||
}
|
||||
else {
|
||||
state.view.SetFollowMouseMode(settings.followMouseOffset, settings.screenEdgePadding);
|
||||
state.isFollowMouse = true;
|
||||
}
|
||||
|
||||
state.view.UpdatePosition();
|
||||
state.animator.Show(state.view.CanvasGroup, settings.fadeDuration, null);
|
||||
}
|
||||
|
||||
private void EnsureView(ViewState state) {
|
||||
if(state.view != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PopupReference popupRef;
|
||||
if(canvasParent != null) {
|
||||
popupRef = Object.Instantiate(viewPrefab, canvasParent);
|
||||
}
|
||||
else {
|
||||
popupRef = Object.Instantiate(viewPrefab);
|
||||
}
|
||||
|
||||
var canvas = popupRef.GetComponent<Canvas>();
|
||||
if(canvas != null) {
|
||||
canvas.overrideSorting = true;
|
||||
canvas.sortingOrder = settings.sortingOrder;
|
||||
}
|
||||
|
||||
state.view = new PopupView(popupRef, settings);
|
||||
state.view.SetVisible(false);
|
||||
state.view.SetMaxWidth(settings.maxPopupWidth);
|
||||
}
|
||||
|
||||
private void DismissLowerPriority(int showingPriority) {
|
||||
foreach(var kvp in categories) {
|
||||
var state = kvp.Value;
|
||||
if(state.priority < showingPriority && state.view != null && state.view.IsVisible) {
|
||||
state.isPending = false;
|
||||
state.animator.Hide(state.view.CanvasGroup, settings.fadeDuration, () => {
|
||||
state.view.SetVisible(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ViewState {
|
||||
public PopupView view;
|
||||
public IPopupAnimator animator;
|
||||
public int priority;
|
||||
public float delay;
|
||||
public float delayTimer;
|
||||
public bool isPending;
|
||||
public bool isFollowMouse;
|
||||
public Action<PopupContentBuilder> pendingBuild;
|
||||
public RectTransform pendingAnchor;
|
||||
public AnchorSide pendingAnchorSide;
|
||||
public Vector2? pendingScreenPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupSystem.cs.meta
Normal file
2
Runtime/PopupSystem.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 056ed88d12add674798ad4e6300bf222
|
||||
54
Runtime/PopupTriggerView.cs
Normal file
54
Runtime/PopupTriggerView.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Handles popup behavior for a <see cref="PopupTrigger"/>. Holds the content callback and
|
||||
/// forwards pointer events to the <see cref="IPopupSystem"/>. This is the behavior layer;
|
||||
/// the MonoBehaviour trigger is the reference holder that forwards events here.
|
||||
/// </summary>
|
||||
public sealed class PopupTriggerView {
|
||||
readonly IPopupSystem popupSystem;
|
||||
Action<PopupContentBuilder> contentCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new trigger view bound to the given popup system.
|
||||
/// </summary>
|
||||
public PopupTriggerView(IPopupSystem popupSystem) {
|
||||
this.popupSystem = popupSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the content builder callback that will be invoked when the popup is shown.
|
||||
/// </summary>
|
||||
public void SetContent(Action<PopupContentBuilder> callback) {
|
||||
contentCallback = callback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="PopupTrigger"/> when the pointer enters. Reads the trigger's
|
||||
/// category, anchor side, and position mode to show the popup.
|
||||
/// </summary>
|
||||
public void OnPointerEnter(PopupTrigger trigger) {
|
||||
if(popupSystem == null || contentCallback == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(trigger.PositionMode == PopupPositionMode.AnchorToElement) {
|
||||
popupSystem.Show(trigger.Category, contentCallback, (RectTransform)trigger.transform, trigger.AnchorSide);
|
||||
}
|
||||
else {
|
||||
popupSystem.Show(trigger.Category, contentCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="PopupTrigger"/> when the pointer exits. Hides the popup
|
||||
/// for the trigger's category.
|
||||
/// </summary>
|
||||
public void OnPointerExit(PopupTrigger trigger) {
|
||||
popupSystem?.Hide(trigger.Category);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupTriggerView.cs.meta
Normal file
2
Runtime/PopupTriggerView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e2351b6a4b8bf046923790d4d09141c
|
||||
224
Runtime/PopupView.cs
Normal file
224
Runtime/PopupView.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
using System.Collections.Generic;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Jovian.PopupSystem {
|
||||
/// <summary>
|
||||
/// Behavior class for a popup view. Manages the generic grow-only element cache,
|
||||
/// positioning, visibility, and layout. Operates on a <see cref="PopupReference"/>
|
||||
/// MonoBehaviour for scene references.
|
||||
/// </summary>
|
||||
public sealed class PopupView {
|
||||
readonly PopupReference reference;
|
||||
readonly PopupSettings settings;
|
||||
|
||||
// Generic element cache: keyed by element type
|
||||
readonly Dictionary<PopupElementType, List<GameObject>> elementCache = new();
|
||||
readonly Dictionary<PopupElementType, int> elementIndex = new();
|
||||
|
||||
// Positioning state
|
||||
PopupPositionMode positionMode;
|
||||
RectTransform anchorTarget;
|
||||
AnchorSide anchorSide;
|
||||
Vector2 followOffset;
|
||||
float screenEdgePadding;
|
||||
float maxWidth;
|
||||
bool isVisible;
|
||||
bool layoutDirty;
|
||||
Canvas rootCanvas;
|
||||
Camera canvasCamera;
|
||||
|
||||
/// <summary>The underlying MonoBehaviour reference holder.</summary>
|
||||
public PopupReference Reference => reference;
|
||||
|
||||
/// <summary>The CanvasGroup for animation control.</summary>
|
||||
public CanvasGroup CanvasGroup => reference.CanvasGroup;
|
||||
|
||||
/// <summary>The content RectTransform where elements are parented.</summary>
|
||||
public RectTransform Content => reference.Content;
|
||||
|
||||
/// <summary>The root Transform of the popup GameObject.</summary>
|
||||
public Transform Transform => reference.transform;
|
||||
|
||||
/// <summary>Whether the popup is currently visible.</summary>
|
||||
public bool IsVisible => isVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new popup view wrapping the given reference and settings.
|
||||
/// </summary>
|
||||
public PopupView(PopupReference reference, PopupSettings settings) {
|
||||
this.reference = reference;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
// --- Element cache (generic, grow-only) ---
|
||||
|
||||
/// <summary>
|
||||
/// Returns the next available cached element for the given type, or instantiates
|
||||
/// a new one from the settings prefab registry. The element is activated and placed
|
||||
/// at the end of the content layout.
|
||||
/// </summary>
|
||||
public GameObject GetElement(PopupElementType elementType) {
|
||||
if(!elementCache.TryGetValue(elementType, out var cache)) {
|
||||
cache = new List<GameObject>();
|
||||
elementCache[elementType] = cache;
|
||||
elementIndex[elementType] = 0;
|
||||
}
|
||||
|
||||
var index = elementIndex[elementType];
|
||||
if(index < cache.Count) {
|
||||
var existing = cache[index];
|
||||
existing.SetActive(true);
|
||||
existing.transform.SetAsLastSibling();
|
||||
elementIndex[elementType] = index + 1;
|
||||
return existing;
|
||||
}
|
||||
|
||||
var prefab = settings.GetPrefab(elementType);
|
||||
if(prefab == null) {
|
||||
Debug.LogWarning($"[PopupView] No prefab registered for element '{elementType}'");
|
||||
return null;
|
||||
}
|
||||
|
||||
var created = Object.Instantiate(prefab, reference.Content);
|
||||
created.SetActive(true);
|
||||
created.transform.SetAsLastSibling();
|
||||
cache.Add(created);
|
||||
elementIndex[elementType] = index + 1;
|
||||
return created;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates all cached content elements and marks layout as dirty.
|
||||
/// </summary>
|
||||
public void ClearContent() {
|
||||
foreach(var kvp in elementCache) {
|
||||
var cache = kvp.Value;
|
||||
var activeCount = elementIndex[kvp.Key];
|
||||
for(int i = 0; i < activeCount; i++) {
|
||||
cache[i].SetActive(false);
|
||||
}
|
||||
elementIndex[kvp.Key] = 0;
|
||||
}
|
||||
layoutDirty = true;
|
||||
}
|
||||
|
||||
// --- Visibility ---
|
||||
|
||||
/// <summary>Shows or hides the popup GameObject. Resets alpha to 0 when hiding.</summary>
|
||||
public void SetVisible(bool visible) {
|
||||
isVisible = visible;
|
||||
reference.gameObject.SetActive(visible);
|
||||
if(!visible) {
|
||||
reference.CanvasGroup.alpha = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Constrains the popup's horizontal size to the given maximum width in pixels.</summary>
|
||||
public void SetMaxWidth(float maxPopupWidth) {
|
||||
maxWidth = maxPopupWidth;
|
||||
if(maxWidth > 0f) {
|
||||
var rt = (RectTransform)reference.transform;
|
||||
var size = rt.sizeDelta;
|
||||
size.x = Mathf.Min(size.x, maxWidth);
|
||||
rt.sizeDelta = size;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Positioning ---
|
||||
|
||||
/// <summary>Configures the popup to anchor to a target element on the specified side.</summary>
|
||||
public void SetAnchorMode(RectTransform target, AnchorSide side, float edgePadding) {
|
||||
positionMode = PopupPositionMode.AnchorToElement;
|
||||
anchorTarget = target;
|
||||
anchorSide = side;
|
||||
screenEdgePadding = edgePadding;
|
||||
}
|
||||
|
||||
/// <summary>Configures the popup to follow the mouse cursor with the given offset.</summary>
|
||||
public void SetFollowMouseMode(Vector2 offset, float edgePadding) {
|
||||
positionMode = PopupPositionMode.FollowMouse;
|
||||
followOffset = offset;
|
||||
screenEdgePadding = edgePadding;
|
||||
}
|
||||
|
||||
/// <summary>Positions the popup at a fixed screen coordinate with edge clamping.</summary>
|
||||
public void SetFixedPosition(Vector2 screenPos, float edgePadding) {
|
||||
positionMode = PopupPositionMode.AnchorToElement;
|
||||
anchorTarget = null;
|
||||
screenEdgePadding = edgePadding;
|
||||
PositionAtScreenPoint(screenPos);
|
||||
}
|
||||
|
||||
/// <summary>Updates the popup position based on the current mode (follow mouse or anchored).</summary>
|
||||
public void UpdatePosition() {
|
||||
if(positionMode == PopupPositionMode.FollowMouse) {
|
||||
PositionAtScreenPoint(Mouse.current.position.ReadValue() + followOffset);
|
||||
}
|
||||
else if(anchorTarget != null) {
|
||||
PositionAnchoredTo(anchorTarget, anchorSide);
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheCanvas() {
|
||||
if(rootCanvas != null) {
|
||||
return;
|
||||
}
|
||||
rootCanvas = reference.GetComponentInParent<Canvas>()?.rootCanvas;
|
||||
canvasCamera = rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay
|
||||
? rootCanvas.worldCamera : null;
|
||||
}
|
||||
|
||||
private void PositionAnchoredTo(RectTransform target, AnchorSide side) {
|
||||
CacheCanvas();
|
||||
var targetRect = GetScreenRect(target, canvasCamera);
|
||||
var popupRect = GetScreenRect((RectTransform)reference.transform, canvasCamera);
|
||||
var popupSize = popupRect.size;
|
||||
|
||||
var pos = side switch {
|
||||
AnchorSide.Below => new Vector2(targetRect.center.x - popupSize.x * 0.5f, targetRect.yMin - popupSize.y),
|
||||
AnchorSide.Above => new Vector2(targetRect.center.x - popupSize.x * 0.5f, targetRect.yMax),
|
||||
AnchorSide.Left => new Vector2(targetRect.xMin - popupSize.x, targetRect.center.y - popupSize.y * 0.5f),
|
||||
AnchorSide.Right => new Vector2(targetRect.xMax, targetRect.center.y - popupSize.y * 0.5f),
|
||||
_ => targetRect.center
|
||||
};
|
||||
|
||||
PositionAtScreenPoint(pos);
|
||||
}
|
||||
|
||||
private void PositionAtScreenPoint(Vector2 screenPos) {
|
||||
CacheCanvas();
|
||||
var rt = (RectTransform)reference.transform;
|
||||
if(layoutDirty) {
|
||||
LayoutRebuilder.ForceRebuildLayoutImmediate(reference.Content);
|
||||
layoutDirty = false;
|
||||
}
|
||||
var popupSize = GetScreenRect(rt, canvasCamera).size;
|
||||
|
||||
// Clamp to screen
|
||||
screenPos.x = Mathf.Clamp(screenPos.x, screenEdgePadding, Screen.width - popupSize.x - screenEdgePadding);
|
||||
screenPos.y = Mathf.Clamp(screenPos.y, screenEdgePadding, Screen.height - popupSize.y - screenEdgePadding);
|
||||
|
||||
// Convert screen position to parent local space
|
||||
var parentRt = rt.parent as RectTransform;
|
||||
if(parentRt != null) {
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(parentRt, screenPos, canvasCamera, out var localPos);
|
||||
rt.localPosition = localPos;
|
||||
}
|
||||
else {
|
||||
rt.position = screenPos;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Vector3[] cornersBuffer = new Vector3[4];
|
||||
|
||||
private static Rect GetScreenRect(RectTransform rt, Camera camera) {
|
||||
rt.GetWorldCorners(cornersBuffer);
|
||||
var min = RectTransformUtility.WorldToScreenPoint(camera, cornersBuffer[0]);
|
||||
var max = RectTransformUtility.WorldToScreenPoint(camera, cornersBuffer[2]);
|
||||
return new Rect(min, max - min);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/PopupView.cs.meta
Normal file
2
Runtime/PopupView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18ebd1b0205e20440aa4c4991b43cc46
|
||||
8
Runtime/UI.meta
Normal file
8
Runtime/UI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4459a298af1a37f47af7b7b70655ee0d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
23
Runtime/UI/PopupReference.cs
Normal file
23
Runtime/UI/PopupReference.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Jovian.PopupSystem.UI {
|
||||
/// <summary>
|
||||
/// Reference-only MonoBehaviour for a popup prefab. Holds serialized scene references
|
||||
/// to the content container, canvas group, and background. All behavior is in
|
||||
/// <see cref="PopupView"/>.
|
||||
/// </summary>
|
||||
public class PopupReference : MonoBehaviour {
|
||||
[SerializeField] RectTransform content;
|
||||
[SerializeField] CanvasGroup canvasGroup;
|
||||
[SerializeField] RectTransform background;
|
||||
|
||||
/// <summary>The content RectTransform where popup elements are parented.</summary>
|
||||
public RectTransform Content => content;
|
||||
|
||||
/// <summary>The CanvasGroup for fade animation control.</summary>
|
||||
public CanvasGroup CanvasGroup => canvasGroup;
|
||||
|
||||
/// <summary>The background RectTransform that sizes to content.</summary>
|
||||
public RectTransform Background => background;
|
||||
}
|
||||
}
|
||||
2
Runtime/UI/PopupReference.cs.meta
Normal file
2
Runtime/UI/PopupReference.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc25da4712d7cc4419eb6f364e032431
|
||||
48
Runtime/UI/PopupTrigger.cs
Normal file
48
Runtime/UI/PopupTrigger.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace Jovian.PopupSystem.UI {
|
||||
/// <summary>
|
||||
/// Reference holder MonoBehaviour for popup triggers. Attach to any UI element with a
|
||||
/// Graphic component (Image, TMP_Text, etc.) that has Raycast Target enabled.
|
||||
/// Configure category, anchor side, and position mode in the Inspector.
|
||||
/// Forwards pointer events to the bound <see cref="PopupTriggerView"/>.
|
||||
/// </summary>
|
||||
public class PopupTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
|
||||
[SerializeField] PopupCategory category;
|
||||
[SerializeField] AnchorSide anchorSide = AnchorSide.Below;
|
||||
[SerializeField] PopupPositionMode positionMode = PopupPositionMode.AnchorToElement;
|
||||
|
||||
PopupTriggerView handler;
|
||||
|
||||
/// <summary>The popup category this trigger belongs to.</summary>
|
||||
public PopupCategory Category => category;
|
||||
|
||||
/// <summary>Which side of this element the popup anchors to.</summary>
|
||||
public AnchorSide AnchorSide => anchorSide;
|
||||
|
||||
/// <summary>Whether the popup anchors to this element or follows the mouse.</summary>
|
||||
public PopupPositionMode PositionMode => positionMode;
|
||||
|
||||
/// <summary>The bound behavior handler. Null until <see cref="Bind"/> is called.</summary>
|
||||
public PopupTriggerView Handler => handler;
|
||||
|
||||
/// <summary>
|
||||
/// Binds a <see cref="PopupTriggerView"/> to this trigger. Called automatically
|
||||
/// by <see cref="IPopupSystem.ScanTriggers"/> or <see cref="IPopupSystem.InitializeTriggersInChildren"/>.
|
||||
/// </summary>
|
||||
public void Bind(PopupTriggerView view) {
|
||||
handler = view;
|
||||
}
|
||||
|
||||
/// <summary>Forwards pointer enter to the bound handler.</summary>
|
||||
public void OnPointerEnter(PointerEventData eventData) {
|
||||
handler?.OnPointerEnter(this);
|
||||
}
|
||||
|
||||
/// <summary>Forwards pointer exit to the bound handler.</summary>
|
||||
public void OnPointerExit(PointerEventData eventData) {
|
||||
handler?.OnPointerExit(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Runtime/UI/PopupTrigger.cs.meta
Normal file
2
Runtime/UI/PopupTrigger.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ef9d21a19cd4db4f9d5491202547c05
|
||||
160
Samples~/Prefabs/PopupHeader.prefab
Normal file
160
Samples~/Prefabs/PopupHeader.prefab
Normal file
@@ -0,0 +1,160 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &7034836061828108288
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1241885294582312999}
|
||||
- component: {fileID: 1942692710355281447}
|
||||
- component: {fileID: 6612787789151041457}
|
||||
- component: {fileID: 743893275569378137}
|
||||
m_Layer: 5
|
||||
m_Name: PopupHeader
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1241885294582312999
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7034836061828108288}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 741.369, y: -210.32233}
|
||||
m_SizeDelta: {x: 214.8432, y: 16}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &1942692710355281447
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7034836061828108288}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &6612787789151041457
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7034836061828108288}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: New Text
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_sharedMaterial: {fileID: 9074173216178389243, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 16
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 5
|
||||
m_fontSizeMax: 16
|
||||
m_fontStyle: 17
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &743893275569378137
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7034836061828108288}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: 1
|
||||
m_LayoutPriority: 1
|
||||
98
Samples~/Prefabs/PopupIcon.prefab
Normal file
98
Samples~/Prefabs/PopupIcon.prefab
Normal file
@@ -0,0 +1,98 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &5887814251614319338
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3721371113883694790}
|
||||
- component: {fileID: 5474191059961008429}
|
||||
- component: {fileID: 7093821785826926595}
|
||||
- component: {fileID: 6531872381202374245}
|
||||
m_Layer: 5
|
||||
m_Name: PopupIcon
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3721371113883694790
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5887814251614319338}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 989.9083, y: -555.6331}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5474191059961008429
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5887814251614319338}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7093821785826926595
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5887814251614319338}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: ea02ea44fa86ee445be0f7ca82098b75, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 1
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &6531872381202374245
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5887814251614319338}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
292
Samples~/Prefabs/PopupReferencePrefab.prefab
Normal file
292
Samples~/Prefabs/PopupReferencePrefab.prefab
Normal file
@@ -0,0 +1,292 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1599460330468667833
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 623181081371217224}
|
||||
- component: {fileID: 1835601435911948781}
|
||||
- component: {fileID: 695849844002832445}
|
||||
- component: {fileID: 3081303906751693297}
|
||||
- component: {fileID: -4214546602618600400}
|
||||
- component: {fileID: 7236468329886607693}
|
||||
m_Layer: 5
|
||||
m_Name: PopupReferencePrefab
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &623181081371217224
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8899521584296352500}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 300, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!225 &1835601435911948781
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!114 &695849844002832445
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bc25da4712d7cc4419eb6f364e032431, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Jovian.PopupSystem::Jovian.PopupSystem.UI.PopupReference
|
||||
content: {fileID: 176628901263125209}
|
||||
canvasGroup: {fileID: 1835601435911948781}
|
||||
background: {fileID: 8899521584296352500}
|
||||
--- !u!223 &3081303906751693297
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 2
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_VertexColorAlwaysGammaSpace: 0
|
||||
m_AdditionalShaderChannelsFlag: 25
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 100
|
||||
m_TargetDisplay: 0
|
||||
--- !u!114 &-4214546602618600400
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler
|
||||
m_UiScaleMode: 1
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0.5
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
m_PresetInfoIsWorld: 1
|
||||
--- !u!114 &7236468329886607693
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1599460330468667833}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &3774543863822571266
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 176628901263125209}
|
||||
- component: {fileID: 2618782962856630769}
|
||||
- component: {fileID: 4695064839375127024}
|
||||
- component: {fileID: 8584485639437491102}
|
||||
- component: {fileID: 7537071497970891545}
|
||||
m_Layer: 5
|
||||
m_Name: Content
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &176628901263125209
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3774543863822571266}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 8899521584296352500}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &2618782962856630769
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3774543863822571266}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 8
|
||||
m_Right: 8
|
||||
m_Top: 8
|
||||
m_Bottom: 8
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 3.82
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 0
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!222 &4695064839375127024
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3774543863822571266}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8584485639437491102
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3774543863822571266}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.1509434, g: 0.116711326, b: 0.088999644, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 52125a3c3df558448a5af5a04dbf8d2d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &7537071497970891545
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3774543863822571266}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &7921791084240859601
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8899521584296352500}
|
||||
- component: {fileID: 4414385109869753182}
|
||||
m_Layer: 5
|
||||
m_Name: Background
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8899521584296352500
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7921791084240859601}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 176628901263125209}
|
||||
m_Father: {fileID: 623181081371217224}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: -0.000015258789, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &4414385109869753182
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7921791084240859601}
|
||||
m_CullTransparentMesh: 1
|
||||
98
Samples~/Prefabs/PopupSeparator.prefab
Normal file
98
Samples~/Prefabs/PopupSeparator.prefab
Normal file
@@ -0,0 +1,98 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &6770634903822758885
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6952702389074691349}
|
||||
- component: {fileID: 8646545094697898389}
|
||||
- component: {fileID: 4190588985333916705}
|
||||
- component: {fileID: 4150277454754236166}
|
||||
m_Layer: 5
|
||||
m_Name: PopupSeparator
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6952702389074691349
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6770634903822758885}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 5.3594}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &8646545094697898389
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6770634903822758885}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4190588985333916705
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6770634903822758885}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 0.61809045, b: 0.15566039, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &4150277454754236166
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6770634903822758885}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
376
Samples~/Prefabs/PopupStat.prefab
Normal file
376
Samples~/Prefabs/PopupStat.prefab
Normal file
@@ -0,0 +1,376 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3992841297615171806
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 292870618973774166}
|
||||
- component: {fileID: 4060824052845831606}
|
||||
- component: {fileID: 572642145995679888}
|
||||
m_Layer: 5
|
||||
m_Name: label
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &292870618973774166
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3992841297615171806}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1843470073663794312}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 177.619, y: 25.6566}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4060824052845831606
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3992841297615171806}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &572642145995679888
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3992841297615171806}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: New Text
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_sharedMaterial: {fileID: 9074173216178389243, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 16
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 5
|
||||
m_fontSizeMax: 16
|
||||
m_fontStyle: 17
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &6246834368258800846
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1843470073663794312}
|
||||
- component: {fileID: 7829576473989485776}
|
||||
- component: {fileID: 5426390226938478828}
|
||||
- component: {fileID: 2356989198378852018}
|
||||
m_Layer: 0
|
||||
m_Name: PopupStat
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1843470073663794312
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6246834368258800846}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 292870618973774166}
|
||||
- {fileID: 8849778187297648043}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 835.73267, y: -543.18}
|
||||
m_SizeDelta: {x: 308.5346, y: 25.640076}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!114 &7829576473989485776
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6246834368258800846}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 18
|
||||
m_Right: 10
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 5.4
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 0
|
||||
m_ChildControlHeight: 0
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &5426390226938478828
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6246834368258800846}
|
||||
m_Enabled: 0
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 0
|
||||
--- !u!114 &2356989198378852018
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6246834368258800846}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: 1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &9078345592336978365
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8849778187297648043}
|
||||
- component: {fileID: 7828883841352225497}
|
||||
- component: {fileID: 6763883082192230688}
|
||||
m_Layer: 5
|
||||
m_Name: value
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8849778187297648043
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 9078345592336978365}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1843470073663794312}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 178.0124, y: 25.64}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7828883841352225497
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 9078345592336978365}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &6763883082192230688
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 9078345592336978365}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: New Text
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_sharedMaterial: {fileID: 9074173216178389243, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 16
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 1.5
|
||||
m_fontSizeMax: 16
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
184
Samples~/Prefabs/PopupText.prefab
Normal file
184
Samples~/Prefabs/PopupText.prefab
Normal file
@@ -0,0 +1,184 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3157287847714375358
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3436634297340404643}
|
||||
- component: {fileID: 386873398398603487}
|
||||
- component: {fileID: 2506259255305457008}
|
||||
- component: {fileID: 8858913019524689709}
|
||||
- component: {fileID: 6923921070612219825}
|
||||
m_Layer: 5
|
||||
m_Name: PopupText
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3436634297340404643
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3157287847714375358}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 705.51843, y: -303.7433}
|
||||
m_SizeDelta: {x: 133.05402, y: 0}
|
||||
m_Pivot: {x: 0, y: 1}
|
||||
--- !u!222 &386873398398603487
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3157287847714375358}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2506259255305457008
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3157287847714375358}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: New Text New TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew Text New TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew Text New TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew TextNew
|
||||
TextNew TextNew TextNew Text
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_sharedMaterial: {fileID: 9074173216178389243, guid: a0ee74bf6f853704a8a568d5ef638ee9, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 12
|
||||
m_fontSizeBase: 36
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
m_fontSizeMin: 1.5
|
||||
m_fontSizeMax: 12
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &8858913019524689709
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3157287847714375358}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: 1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!114 &6923921070612219825
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3157287847714375358}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
58
Samples~/README.md
Normal file
58
Samples~/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Popup System Samples
|
||||
|
||||
## Contents
|
||||
|
||||
### Prefabs
|
||||
|
||||
Reference prefabs for the popup system. Copy these into your project as a starting point. After copying, add entries to your `PopupSettings` asset's Element Prefabs list mapping `PopupElementType` values to these prefabs.
|
||||
|
||||
| Prefab | PopupElementType | Description |
|
||||
|---|---|---|
|
||||
| `PopupReferencePrefab` | N/A | Main popup container with Canvas, CanvasGroup, Background, and Content |
|
||||
| `PopupHeader` | `Header` ("header") | Header text element (TMP_Text, bold, larger font) |
|
||||
| `PopupText` | `Text` ("text") | Body text element (TMP_Text, regular) |
|
||||
| `PopupStat` | `LabelValueText` ("label_value_text") | Label + value row (HorizontalLayoutGroup with two TMP_Text children) |
|
||||
| `PopupIcon` | `Image` ("image") | Image element for icons or artwork |
|
||||
| `PopupSeparator` | `Separator` ("separator") | Horizontal divider line (Image, thin) |
|
||||
|
||||
To add variants, duplicate a prefab, style it differently, and register it with a variant type. Use `PopupElementType.Header.Variant("gold")` in code, and set the type to "header_gold" in the PopupSettings Inspector.
|
||||
|
||||
### Settings
|
||||
|
||||
| Asset | Description |
|
||||
|---|---|
|
||||
| `PopupSettings` | Pre-configured PopupSettings ScriptableObject with sensible defaults |
|
||||
|
||||
### Scripts
|
||||
|
||||
| Script | Description |
|
||||
|---|---|
|
||||
| `PopupSystemExample` | Basic setup with auto-scanned triggers, `GetTriggerHandler` by name, and `GetTriggerHandlers` by category |
|
||||
| `DynamicTriggersExample` | Setting up triggers on dynamically instantiated UI using `InitializeTriggersInChildren` with (trigger, view) callback |
|
||||
| `CodeOnlyPopupExample` | Showing popups from code (anchored, fixed position, follow mouse), `PopupElementType` variants, and generic `Add()` for custom types |
|
||||
|
||||
### Architecture Overview
|
||||
|
||||
```
|
||||
PopupTrigger (MonoBehaviour) -- reference holder, forwards pointer events
|
||||
|
|
||||
PopupTriggerView (C# class) -- behavior: calls IPopupSystem.Show/Hide
|
||||
|
|
||||
IPopupSystem / PopupSystem -- manages categories, delays, priority, triggers
|
||||
|
|
||||
PopupView (C# class) -- behavior: generic element cache, positioning
|
||||
|
|
||||
PopupReference (MonoBehaviour) -- reference holder: content, canvasGroup, background
|
||||
|
|
||||
PopupSettings (ScriptableObject) -- configuration + element prefab registry (PopupElementType -> prefab)
|
||||
|
|
||||
PopupElementType (struct) -- type-safe element identifier (Header, Text, LabelValueText, Image, Separator + custom)
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
1. Import the samples via the Unity Package Manager (select the package, expand Samples, click Import)
|
||||
2. Copy the prefabs into your project's Prefabs folder
|
||||
3. Create a PopupSettings asset or use the provided one
|
||||
4. Add Element Prefab entries to PopupSettings using the dropdown (Header, Text, LabelValueText, Image, Separator) mapped to the copied prefabs
|
||||
5. Reference the example scripts for integration patterns
|
||||
91
Samples~/Scripts/CodeOnlyPopupExample.cs
Normal file
91
Samples~/Scripts/CodeOnlyPopupExample.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using Jovian.PopupSystem;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Example: Showing popups from code without PopupTrigger components.
|
||||
///
|
||||
/// Use this approach for confirmation dialogs, tutorial tips, or any popup
|
||||
/// that is triggered by game logic rather than hover events.
|
||||
/// Also demonstrates PopupElementType variants and the generic Add() method.
|
||||
/// </summary>
|
||||
public class CodeOnlyPopupExample : MonoBehaviour {
|
||||
[SerializeField] PopupSettings popupSettings;
|
||||
[SerializeField] PopupReference popupReferencePrefab;
|
||||
[SerializeField] Transform canvasRoot;
|
||||
[SerializeField] RectTransform targetElement;
|
||||
|
||||
// Custom element type defined in game code
|
||||
static readonly PopupElementType BadgeElement = new("badge");
|
||||
|
||||
IPopupSystem popupSystem;
|
||||
|
||||
void Start() {
|
||||
popupSystem = new PopupSystem(popupSettings, popupReferencePrefab, canvasRoot);
|
||||
popupSystem.RegisterCategory(PopupCategory.General, priority: 1);
|
||||
}
|
||||
|
||||
void Update() {
|
||||
popupSystem?.Tick(Time.deltaTime);
|
||||
|
||||
// Show anchored to an element
|
||||
if(Input.GetKeyDown(KeyCode.Alpha1)) {
|
||||
popupSystem.Show(PopupCategory.General, builder => {
|
||||
builder
|
||||
.AddText("Anchored Popup", PopupElementType.Header)
|
||||
.AddText("This popup is anchored to a UI element.", PopupElementType.Text);
|
||||
}, targetElement, AnchorSide.Right);
|
||||
}
|
||||
|
||||
// Show at a fixed screen position
|
||||
if(Input.GetKeyDown(KeyCode.Alpha2)) {
|
||||
popupSystem.ShowAtPosition(PopupCategory.General, builder => {
|
||||
builder
|
||||
.AddText("Fixed Position", PopupElementType.Header)
|
||||
.AddText("This popup appears at the center of the screen.", PopupElementType.Text);
|
||||
}, new Vector2(Screen.width * 0.5f, Screen.height * 0.5f));
|
||||
}
|
||||
|
||||
// Show following the mouse
|
||||
if(Input.GetKeyDown(KeyCode.Alpha3)) {
|
||||
popupSystem.Show(PopupCategory.General, builder => {
|
||||
builder
|
||||
.AddText("Follow Mouse", PopupElementType.Header)
|
||||
.AddText("This popup follows the cursor.", PopupElementType.Text);
|
||||
});
|
||||
}
|
||||
|
||||
// Demonstrate variant elements
|
||||
// Requires "header_gold" and "separator_thick" entries in PopupSettings.elementPrefabs
|
||||
if(Input.GetKeyDown(KeyCode.Alpha4)) {
|
||||
popupSystem.Show(PopupCategory.General, builder => {
|
||||
builder
|
||||
.AddText("Legendary Item", PopupElementType.Header.Variant("gold"))
|
||||
.AddSeparator(PopupElementType.Separator.Variant("thick"))
|
||||
.AddNameValue("Damage", "150", PopupElementType.LabelValueText)
|
||||
.AddText("A weapon forged in dragon fire.", "FF6600", PopupElementType.Text);
|
||||
}, targetElement, AnchorSide.Below);
|
||||
}
|
||||
|
||||
// Demonstrate generic Add() for fully custom elements
|
||||
// Requires a "badge" entry in PopupSettings.elementPrefabs
|
||||
if(Input.GetKeyDown(KeyCode.Alpha5)) {
|
||||
popupSystem.Show(PopupCategory.General, builder => {
|
||||
builder.AddText("Custom Element", PopupElementType.Header);
|
||||
var badge = builder.Add(BadgeElement);
|
||||
if(badge != null) {
|
||||
// Access any components on the custom prefab
|
||||
// badge.GetComponent<MyBadgeComponent>().SetData(...);
|
||||
}
|
||||
}, targetElement);
|
||||
}
|
||||
|
||||
if(Input.GetKeyDown(KeyCode.Escape)) {
|
||||
popupSystem.HideAll();
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy() {
|
||||
popupSystem?.Dispose();
|
||||
}
|
||||
}
|
||||
48
Samples~/Scripts/DynamicTriggersExample.cs
Normal file
48
Samples~/Scripts/DynamicTriggersExample.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Jovian.PopupSystem;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Example: Using PopupSystem with dynamically instantiated UI elements.
|
||||
///
|
||||
/// When UI elements are created at runtime (e.g. inventory slots, party member portraits),
|
||||
/// use InitializeTriggersInChildren to scan, bind, and configure triggers after instantiation.
|
||||
/// The callback receives both the trigger (MonoBehaviour, for hierarchy queries) and the
|
||||
/// view (behavior handler, for setting content).
|
||||
/// </summary>
|
||||
public class DynamicTriggersExample : MonoBehaviour {
|
||||
[SerializeField] PopupSettings popupSettings;
|
||||
[SerializeField] PopupReference popupReferencePrefab;
|
||||
[SerializeField] Transform canvasRoot;
|
||||
[SerializeField] Transform slotsContainer;
|
||||
[SerializeField] GameObject slotPrefab;
|
||||
|
||||
IPopupSystem popupSystem;
|
||||
|
||||
void Start() {
|
||||
popupSystem = new PopupSystem(popupSettings, popupReferencePrefab, canvasRoot);
|
||||
popupSystem.RegisterCategory(PopupCategory.Item, priority: 5);
|
||||
|
||||
for(int i = 0; i < 5; i++) {
|
||||
Instantiate(slotPrefab, slotsContainer);
|
||||
}
|
||||
|
||||
popupSystem.InitializeTriggersInChildren(slotsContainer, (trigger, view) => {
|
||||
var slotName = trigger.gameObject.name;
|
||||
view.SetContent(builder => {
|
||||
builder
|
||||
.AddText(slotName, PopupElementType.Header)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddText("This is a dynamically created slot.", PopupElementType.Text);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Update() {
|
||||
popupSystem?.Tick(Time.deltaTime);
|
||||
}
|
||||
|
||||
void OnDestroy() {
|
||||
popupSystem?.Dispose();
|
||||
}
|
||||
}
|
||||
67
Samples~/Scripts/PopupSystemExample.cs
Normal file
67
Samples~/Scripts/PopupSystemExample.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Jovian.PopupSystem;
|
||||
using Jovian.PopupSystem.UI;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Example: Setting up PopupSystem with auto-scanned triggers.
|
||||
///
|
||||
/// 1. Attach this to a GameObject in your scene.
|
||||
/// 2. Assign the PopupSettings asset and PopupReference prefab.
|
||||
/// 3. Set canvasRoot to the root Canvas that contains your UI and PopupTrigger components.
|
||||
/// 4. Place PopupTrigger components on any UI elements that should show popups on hover.
|
||||
/// 5. The system auto-scans triggers on creation. Use GetTriggerHandler() to set content.
|
||||
///
|
||||
/// Element prefabs are configured in PopupSettings via PopupElementType.
|
||||
/// Add entries mapping types (header, text, label_value_text, separator, image) to prefabs.
|
||||
/// </summary>
|
||||
public class PopupSystemExample : MonoBehaviour {
|
||||
[SerializeField] PopupSettings popupSettings;
|
||||
[SerializeField] PopupReference popupReferencePrefab;
|
||||
[SerializeField] Transform canvasRoot;
|
||||
|
||||
IPopupSystem popupSystem;
|
||||
|
||||
void Start() {
|
||||
popupSystem = new PopupSystem(popupSettings, popupReferencePrefab, canvasRoot);
|
||||
|
||||
popupSystem.RegisterCategory(PopupCategory.Character, priority: 10);
|
||||
popupSystem.RegisterCategory(PopupCategory.Item, priority: 5);
|
||||
popupSystem.RegisterCategory(PopupCategory.General, priority: 1);
|
||||
|
||||
// Set content on an auto-scanned trigger by GameObject name.
|
||||
var characterHandler = popupSystem.GetTriggerHandler("CharacterPortrait");
|
||||
characterHandler?.SetContent(builder => {
|
||||
builder
|
||||
.AddText("Kael", PopupElementType.Header)
|
||||
.AddText("Human Warrior", "CCCCCC", PopupElementType.Text)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddNameValue("Health", 55, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Mana", 42, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Level", 1, PopupElementType.LabelValueText)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddNameValue("Might", 8, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Reflex", 2, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Knowledge", 5, PopupElementType.LabelValueText)
|
||||
.AddNameValue("Perception", 1, PopupElementType.LabelValueText);
|
||||
});
|
||||
|
||||
// Set content on all triggers of a category.
|
||||
foreach(var handler in popupSystem.GetTriggerHandlers(PopupCategory.Item)) {
|
||||
handler.SetContent(builder => {
|
||||
builder
|
||||
.AddText("Health Potion", PopupElementType.Header)
|
||||
.AddSeparator(PopupElementType.Separator)
|
||||
.AddText("Restores a moderate amount of health.", PopupElementType.Text)
|
||||
.AddNameValue("Heal Amount", 50, PopupElementType.LabelValueText);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Update() {
|
||||
popupSystem?.Tick(Time.deltaTime);
|
||||
}
|
||||
|
||||
void OnDestroy() {
|
||||
popupSystem?.Dispose();
|
||||
}
|
||||
}
|
||||
44
Samples~/Settings/PopupSettings.asset
Normal file
44
Samples~/Settings/PopupSettings.asset
Normal file
@@ -0,0 +1,44 @@
|
||||
%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: e38e313f3665d464b82b22699b2a4634, type: 3}
|
||||
m_Name: PopupSettings
|
||||
m_EditorClassIdentifier: Jovian.PopupSystem::Jovian.PopupSystem.PopupSettings
|
||||
popupDelay: 0.4
|
||||
fadeDuration: 0.2
|
||||
defaultAnchorSide: 3
|
||||
screenEdgePadding: 10
|
||||
maxPopupWidth: 400
|
||||
sortingOrder: 100
|
||||
followMouseOffset: {x: 15, y: -15}
|
||||
touchHoldDuration: 0.6
|
||||
gamepadFocusTrigger: 1
|
||||
elementPrefabs:
|
||||
- type:
|
||||
id: header
|
||||
prefab: {fileID: 7034836061828108288, guid: dfc1bc0bd5b4905409615c3e770a5b77, type: 3}
|
||||
- type:
|
||||
id: image
|
||||
prefab: {fileID: 5887814251614319338, guid: 5e715f4b614d02b4fa0b4d3fcfe3c053, type: 3}
|
||||
- type:
|
||||
id: label_value_text
|
||||
prefab: {fileID: 6770634903822758885, guid: 7ccdfa1a2079db044be4b1684303ec7f, type: 3}
|
||||
- type:
|
||||
id: separator
|
||||
prefab: {fileID: 6770634903822758885, guid: 7ccdfa1a2079db044be4b1684303ec7f, type: 3}
|
||||
- type:
|
||||
id: text
|
||||
prefab: {fileID: 3157287847714375358, guid: bfa97c92d1878cc448ddc7dc456f4b17, type: 3}
|
||||
categoryPriorities:
|
||||
- category:
|
||||
id: Character
|
||||
priority: 0
|
||||
categoryDelayOverrides: []
|
||||
20
package.json
Normal file
20
package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "com.jovian.popup-system",
|
||||
"version": "0.1.0",
|
||||
"displayName": "Jovian Popup System",
|
||||
"description": "A lightweight, low-allocation popup and tooltip system with category-based isolation, fluent content builder, and extensible animations.",
|
||||
"unity": "2022.3",
|
||||
"dependencies": {
|
||||
"com.unity.textmeshpro": "3.0.6",
|
||||
"com.unity.inputsystem": "1.18.0",
|
||||
"com.unity.nuget.newtonsoft-json": "3.2.1"
|
||||
},
|
||||
"keywords": [
|
||||
"popup",
|
||||
"tooltip",
|
||||
"ui"
|
||||
],
|
||||
"author": {
|
||||
"name": "Jovian"
|
||||
}
|
||||
}
|
||||
7
package.json.meta
Normal file
7
package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3120e52713c91c44d9790e65c94b0869
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user