├── .gitattributes
├── .github
└── workflows
│ └── generate-docs.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── CHANGELOG.md
├── CHANGELOG.md.meta
├── Documentation~
├── articles
│ ├── index.md
│ ├── installation.md
│ ├── letterboxing.md
│ ├── menus.md
│ └── screen-size.md
├── data
│ ├── header.json
│ └── sidenav.json
└── images
│ └── letterboxing.jpg
├── Editor.meta
├── Editor
├── UIGradientShaderGUI.cs
├── UIGradientShaderGUI.cs.meta
├── Zigurous.UI.Editor.asmdef
└── Zigurous.UI.Editor.asmdef.meta
├── LICENSE.md
├── LICENSE.md.meta
├── Materials.meta
├── Materials
├── UIInverseMask-Content.mat
├── UIInverseMask-Content.mat.meta
├── UIInverseMask-Cutout.mat
└── UIInverseMask-Cutout.mat.meta
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── CinematicBars.cs
├── CinematicBars.cs.meta
├── Extensions.meta
├── Extensions
│ ├── CanvasExtensions.cs
│ ├── CanvasExtensions.cs.meta
│ ├── GraphicExtensions.cs
│ ├── GraphicExtensions.cs.meta
│ ├── RectTransformExtensions.cs
│ └── RectTransformExtensions.cs.meta
├── InverseMask.cs
├── InverseMask.cs.meta
├── Letterboxing.cs
├── Letterboxing.cs.meta
├── NavigationStack.cs
├── NavigationStack.cs.meta
├── ScreenSizeListener.cs
├── ScreenSizeListener.cs.meta
├── ScrollDirection.cs
├── ScrollDirection.cs.meta
├── ScrollToSelection.cs
├── ScrollToSelection.cs.meta
├── ScrollWithInput.cs
├── ScrollWithInput.cs.meta
├── StretchToScreenSize.cs
├── StretchToScreenSize.cs.meta
├── Zigurous.UI.asmdef
└── Zigurous.UI.asmdef.meta
├── Shaders.meta
├── Shaders
├── UIGradient.shader
└── UIGradient.shader.meta
├── package.json
└── package.json.meta
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.html linguist-detectable=false
2 | *.css linguist-detectable=false
3 | *.js linguist-detectable=false
4 |
--------------------------------------------------------------------------------
/.github/workflows/generate-docs.yml:
--------------------------------------------------------------------------------
1 | name: Generate Docs
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 |
9 | concurrency:
10 | group: ${{ github.workflow }}-${{ github.ref }}
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | generate:
15 | name: Docs
16 | uses: zigurous/docs/.github/workflows/unity-package.yml@main
17 | with:
18 | package_title: "UI Toolkit"
19 | package_base_path: com.zigurous.ui
20 | package_workflow: generate-docs.yml
21 | package_artifact: docs
22 | secrets:
23 | token: ${{ secrets.DOCS_TOKEN }}
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /**/obj/
2 | /**/obj.meta
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | ./docs~/
2 | .github/
3 | .gitattributes
4 | .gitignore
5 | .gitmodules
6 | /**/obj/
7 | /**/obj.meta
8 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry=https://registry.npmjs.org/
2 | @zigurous:registry=https://npm.pkg.github.com
3 | //npm.pkg.github.com/:_authToken=
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [0.3.0] - 2022/11/02
9 |
10 | ### Added
11 |
12 | - UIGradient shader
13 | - Materials for creating inverse masks
14 | - `InverseMask` script to automatically apply inverse mask materials
15 |
16 | ### Changed
17 |
18 | - Renamed `Letterboxing` script to `CinematicBars`
19 | - Added new `Letterboxing` script that changes the camera viewport
20 |
21 | ## [0.2.0] - 2021/07/17
22 |
23 | ### Added
24 |
25 | - Letterboxing
26 | - ScreenSizeListener
27 | - StretchToScreenSize
28 | - CanvasExtensions
29 | - GraphicExtensions
30 | - RectTransformExtensions
31 |
32 | ## [0.1.0] - 2021/07/05
33 |
34 | ### Added
35 |
36 | - NavigationStack
37 | - ScrollToSelection
38 | - ScrollWithInput
39 |
--------------------------------------------------------------------------------
/CHANGELOG.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f3a2dedc0a794cb4c80c7561bacaf129
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Documentation~/articles/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: "/manual"
3 | ---
4 |
5 | # UI Toolkit
6 |
7 | The **UI Toolkit** package contains scripts and utilities for creating UI in Unity projects. The package is intended to solve common problems that arise when developing UI and menus. The package is still early in development, and more functionality will be added over time.
8 |
9 |
10 |
11 | ## Overview
12 |
13 | #### ⚙️ [Installation](/installation)
14 |
15 | #### 🧰 [Scripting API](/api/Zigurous.UI)
16 |
17 | #### 📋 [Changelog](/changelog)
18 |
19 | #### ⚖️ [License](/license)
20 |
21 |
22 |
23 | ## Reference
24 |
25 | #### 📑 [Menu Tools](/manual/menus)
26 |
27 | #### 🎞️ [Letterboxing](/manual/letterboxing)
28 |
29 | #### 📏 [Screen Size](/manual/screen-size)
30 |
--------------------------------------------------------------------------------
/Documentation~/articles/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: "/installation"
3 | ---
4 |
5 | # Installation
6 |
7 | Use the Unity [Package Manager](https://docs.unity3d.com/Manual/upm-ui.html) to install the **UI Toolkit** package.
8 |
9 | 1. Open the Package Manager in `Window > Package Manager`
10 | 2. Click the add (`+`) button in the status bar
11 | 3. Select `Add package from git URL` from the add menu
12 | 4. Enter the following Git URL in the text box and click Add:
13 |
14 | ```http
15 | https://github.com/zigurous/unity-ui-toolkit.git
16 | ```
17 |
18 |
19 |
20 | ## 🏷️ Namespace
21 |
22 | Import the package namespace in each script or file you want to use it. You may need to regenerate project files/assemblies first.
23 |
24 | ```csharp
25 | using Zigurous.UI;
26 | ```
27 |
28 |
29 |
30 | ## 💻 Source Code
31 |
32 | The source code for the **UI Toolkit** package is in the following repository:
33 |
34 | - https://github.com/zigurous/unity-ui-toolkit
35 |
--------------------------------------------------------------------------------
/Documentation~/articles/letterboxing.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: "/manual/letterboxing"
3 | ---
4 |
5 | # Letterboxing
6 |
7 | Letterboxing is the process of changing an image or video's aspect ratio to another format while preserving the original aspect ratio. The resulting image has mattes (black bars) above and below it. The **UI Toolkit** packages includes a [Letterboxing](/api/Zigurous.UI/Letterboxing) script to handle this process. This script is most useful when displaying in-game cutscenes to give it a more cinematic feeling.
8 |
9 | 
10 |
11 |
12 |
13 | ## 🎞️ Cinematic Bars
14 |
15 | Also included in the **UI Toolkit** package is the script [CinematicBars](/api/Zigurous.UI/CinematicBars) which allows you to simulate the letterboxing effect without actually changing the camera's viewport. This script displays the mattes (black bars) as UI elements overlayed in screen space.
16 |
17 | The color and material of the mattes can be customized as well as the desired aspect ratio. The script will animate the mattes in and out simply by enabling or disabling the script.
18 |
--------------------------------------------------------------------------------
/Documentation~/articles/menus.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: "/manual/menus"
3 | ---
4 |
5 | # Menu Tools
6 |
7 | The **UI Toolkit** comes with a few scripts to assist in creating UI menus. There are several common problems that arise, especially in regards to menu navigation and controller-support. Generally speaking, basic navigation in menus across any input device can be achieved out-of-box using Unity's EventSystem component; however, this is not always the case.
8 |
9 |
10 |
11 | ### [NavigationStack](/api/Zigurous.UI/NavigationStack)
12 |
13 | This script manages a stack of game objects (menus) that you can navigate between. As you navigate to other menus or sub-menus, you push the menu's game object onto the stack. Then, when you need to navigate back to the previous menu, you simply pop the game object off the stack. The script can also automatically turn on/off the game objects as they are pushed and popped from the stack. The script also provides an InputAction to handle backwards navigation.
14 |
15 |
16 |
17 | ### [ScrollToSelection](/api/Zigurous.UI/ScrollToSelection)
18 |
19 | This script works in conjunction with the EventSystem to handle scrolling a ScrollRect component to the selected game object. For example, when using a controller you usually do not freely scroll menus that display a list of buttons, such as a level select menu. Rather, you simply navigate up and down to the next or previous button, respectively. The ScrollRect will automatically be scrolled to whichever game object is selected.
20 |
21 |
22 |
23 | ### [ScrollWithInput](/api/Zigurous.UI/ScrollWithInput)
24 |
25 | For other menus that use a ScrollRect component, you may just want to be able to freely scroll up and down. This may not be supported out of the box for controllers, so this script simply exposes an InputAction that you can bind controls to in order to scroll the menu. There is actually nothing specific to controllers in this script, so you can also use it with any kind of input, but generally mouse+keyboard already works with ScrollRect.
26 |
--------------------------------------------------------------------------------
/Documentation~/articles/screen-size.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: "/manual/screen-size"
3 | ---
4 |
5 | # Screen Size
6 |
7 | Detecting changes to the screen size is very common for many different use cases in games. The **UI Toolkit** package includes the singleton [ScreenSizeListener](/api/Zigurous.UI/ScreenSizeListener) that allows you to register a callback to know when the screen size changes.
8 |
9 | ```csharp
10 | ScreenSizeListener.Instance.resized += OnResize;
11 |
12 | private void OnResize(float width, float height)
13 | {
14 | // handle resize here
15 | }
16 | ```
17 |
18 | You can simply get the current screen size too. There seems to be a bug with Unity's `Screen.width` and `Screen.height` because they do not always return the correct values. Using the listener can be more reliable.
19 |
20 | ```csharp
21 | if (ScreenSizeListener.HasInstance)
22 | {
23 | // Individual properties
24 | float width = ScreenSizeListener.Instance.width;
25 | float height = ScreenSizeListener.Instance.height;
26 |
27 | // Single property
28 | Vector2Int size = ScreenSizeListener.Instance.size;
29 | }
30 | ```
31 |
--------------------------------------------------------------------------------
/Documentation~/data/header.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Manual",
4 | "path": "/manual"
5 | },
6 | {
7 | "name": "Scripting API",
8 | "path": "/api"
9 | },
10 | {
11 | "name": "Changelog",
12 | "path": "/changelog"
13 | },
14 | {
15 | "name": "License",
16 | "path": "/license"
17 | }
18 | ]
19 |
--------------------------------------------------------------------------------
/Documentation~/data/sidenav.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "title": "📌 Overview",
4 | "items": [
5 | {
6 | "name": "Getting Started",
7 | "path": "/manual"
8 | },
9 | {
10 | "name": "Installation",
11 | "path": "/installation"
12 | },
13 | {
14 | "name": "Changelog",
15 | "path": "/changelog"
16 | },
17 | {
18 | "name": "License",
19 | "path": "/license"
20 | }
21 | ]
22 | },
23 | {
24 | "title": "📖 Reference",
25 | "items": [
26 | {
27 | "name": "Menu Tools",
28 | "path": "/manual/menus"
29 | },
30 | {
31 | "name": "Letterboxing",
32 | "path": "/manual/letterboxing"
33 | },
34 | {
35 | "name": "Screen Size",
36 | "path": "/manual/screen-size"
37 | }
38 | ]
39 | },
40 | {
41 | "title": "💬 Contact",
42 | "items": [
43 | {
44 | "name": "Discord",
45 | "href": "https://discord.gg/DdYyWVb",
46 | "icon": "launch"
47 | },
48 | {
49 | "name": "Twitter",
50 | "href": "https://twitter.com/zigurous",
51 | "icon": "launch"
52 | }
53 | ]
54 | },
55 | {
56 | "title": "🔗 Other Links",
57 | "items": [
58 | {
59 | "name": "GitHub",
60 | "href": "https://github.com/zigurous/unity-ui-toolkit",
61 | "icon": "launch"
62 | },
63 | {
64 | "name": "Asset Store",
65 | "href": "https://assetstore.unity.com/publishers/51884",
66 | "icon": "launch"
67 | },
68 | {
69 | "name": "YouTube",
70 | "href": "https://youtube.com/c/zigurous?sub_confirmation=1",
71 | "icon": "launch"
72 | },
73 | {
74 | "name": "Patreon",
75 | "href": "https://patreon.com/zigurous",
76 | "icon": "launch"
77 | }
78 | ]
79 | }
80 | ]
81 |
--------------------------------------------------------------------------------
/Documentation~/images/letterboxing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zigurous/unity-ui-toolkit/1c4222df2cd61c737cb239ee3b565d19632f68f8/Documentation~/images/letterboxing.jpg
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d31a4d1c0db7c1040882d97cab645b4d
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/UIGradientShaderGUI.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using UnityEditor;
4 | using UnityEngine;
5 |
6 | namespace Zigurous.UI.Editor
7 | {
8 | public sealed class UIGradientShaderGUI : ShaderGUI
9 | {
10 | public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
11 | {
12 | EditorGUILayout.Space();
13 |
14 | Material material = materialEditor.target as Material;
15 |
16 | if (material == null) {
17 | throw new ArgumentNullException(nameof(material));
18 | }
19 |
20 | GradientColorKey[] colorKeys = Enumerable
21 | .Range(0, material.GetInt("_Colors"))
22 | .Select((s, t) => new GradientColorKey(material.GetColor($"_Color{t}"), material.GetFloat($"_ColorTime{t}")))
23 | .ToArray();
24 |
25 | GradientAlphaKey[] alphaKeys = Enumerable
26 | .Range(0, material.GetInt("_Alphas"))
27 | .Select((s, t) => new GradientAlphaKey(material.GetFloat($"_Alpha{t}"), material.GetFloat($"_AlphaTime{t}")))
28 | .ToArray();
29 |
30 | Gradient gradient = new Gradient();
31 | gradient.SetKeys(colorKeys, alphaKeys);
32 |
33 | EditorGUI.BeginChangeCheck();
34 |
35 | Gradient field = EditorGUILayout.GradientField("Gradient", gradient);
36 |
37 | if (!EditorGUI.EndChangeCheck())
38 | {
39 | base.OnGUI(materialEditor, properties);
40 | return;
41 | }
42 |
43 | for (int i = 0; i < 8; i++)
44 | {
45 | material.SetColor($"_Color{i}", Color.magenta);
46 | material.SetFloat($"_ColorTime{i}", -1f);
47 | material.SetFloat($"_Alpha{i}", -1f);
48 | material.SetFloat($"_AlphaTime{i}", -1f);
49 | }
50 |
51 | for (int i = 0; i < field.colorKeys.Length; i++)
52 | {
53 | material.SetColor($"_Color{i}", field.colorKeys[i].color);
54 | material.SetFloat($"_ColorTime{i}", field.colorKeys[i].time);
55 | }
56 |
57 | for (int i = 0; i < field.alphaKeys.Length; i++)
58 | {
59 | material.SetFloat($"_Alpha{i}", field.alphaKeys[i].alpha);
60 | material.SetFloat($"_AlphaTime{i}", field.alphaKeys[i].time);
61 | }
62 |
63 | material.SetInt("_Colors", field.colorKeys.Length);
64 | material.SetInt("_Alphas", field.alphaKeys.Length);
65 |
66 | EditorUtility.SetDirty(material);
67 |
68 | base.OnGUI(materialEditor, properties);
69 | }
70 |
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/Editor/UIGradientShaderGUI.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 70ee537964b955e46a01339a0d022953
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/Zigurous.UI.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Zigurous.UI.Editor",
3 | "references": [
4 | "Zigurous.UI"
5 | ],
6 | "includePlatforms": [
7 | "Editor"
8 | ],
9 | "excludePlatforms": [],
10 | "allowUnsafeCode": false,
11 | "overrideReferences": false,
12 | "precompiledReferences": [],
13 | "autoReferenced": true,
14 | "defineConstraints": [],
15 | "versionDefines": [],
16 | "noEngineReferences": false
17 | }
--------------------------------------------------------------------------------
/Editor/Zigurous.UI.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ff3e0322a7e9be44b925e33c5f242aed
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Zigurous
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 450148839c6559b40b9e149cc67a954f
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Materials.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 339519c5250b1194c8092af7201caf1d
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Materials/UIInverseMask-Content.mat:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!21 &2100000
4 | Material:
5 | serializedVersion: 6
6 | m_ObjectHideFlags: 0
7 | m_CorrespondingSourceObject: {fileID: 0}
8 | m_PrefabInstance: {fileID: 0}
9 | m_PrefabAsset: {fileID: 0}
10 | m_Name: UIInverseMask-Content
11 | m_Shader: {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
12 | m_ShaderKeywords: ETC1_EXTERNAL_ALPHA
13 | m_LightmapFlags: 4
14 | m_EnableInstancingVariants: 0
15 | m_DoubleSidedGI: 0
16 | m_CustomRenderQueue: -1
17 | stringTagMap: {}
18 | disabledShaderPasses: []
19 | m_SavedProperties:
20 | serializedVersion: 3
21 | m_TexEnvs:
22 | - _BumpMap:
23 | m_Texture: {fileID: 0}
24 | m_Scale: {x: 1, y: 1}
25 | m_Offset: {x: 0, y: 0}
26 | - _DetailAlbedoMap:
27 | m_Texture: {fileID: 0}
28 | m_Scale: {x: 1, y: 1}
29 | m_Offset: {x: 0, y: 0}
30 | - _DetailMask:
31 | m_Texture: {fileID: 0}
32 | m_Scale: {x: 1, y: 1}
33 | m_Offset: {x: 0, y: 0}
34 | - _DetailNormalMap:
35 | m_Texture: {fileID: 0}
36 | m_Scale: {x: 1, y: 1}
37 | m_Offset: {x: 0, y: 0}
38 | - _EmissionMap:
39 | m_Texture: {fileID: 0}
40 | m_Scale: {x: 1, y: 1}
41 | m_Offset: {x: 0, y: 0}
42 | - _MainTex:
43 | m_Texture: {fileID: 0}
44 | m_Scale: {x: 1, y: 1}
45 | m_Offset: {x: 0, y: 0}
46 | - _MetallicGlossMap:
47 | m_Texture: {fileID: 0}
48 | m_Scale: {x: 1, y: 1}
49 | m_Offset: {x: 0, y: 0}
50 | - _OcclusionMap:
51 | m_Texture: {fileID: 0}
52 | m_Scale: {x: 1, y: 1}
53 | m_Offset: {x: 0, y: 0}
54 | - _ParallaxMap:
55 | m_Texture: {fileID: 0}
56 | m_Scale: {x: 1, y: 1}
57 | m_Offset: {x: 0, y: 0}
58 | m_Floats:
59 | - _BumpScale: 1
60 | - _ColorMask: 15
61 | - _Cutoff: 0.5
62 | - _DetailNormalMapScale: 1
63 | - _DstBlend: 0
64 | - _GlossMapScale: 1
65 | - _Glossiness: 0.5
66 | - _GlossyReflections: 1
67 | - _Metallic: 0
68 | - _Mode: 0
69 | - _OcclusionStrength: 1
70 | - _Parallax: 0.02
71 | - _SmoothnessTextureChannel: 0
72 | - _SpecularHighlights: 1
73 | - _SrcBlend: 1
74 | - _Stencil: 2
75 | - _StencilComp: 3
76 | - _StencilOp: 0
77 | - _StencilReadMask: 1
78 | - _StencilWriteMask: 0
79 | - _UVSec: 0
80 | - _UseUIAlphaClip: 0
81 | - _ZWrite: 1
82 | m_Colors:
83 | - _Color: {r: 1, g: 1, b: 1, a: 1}
84 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
85 |
--------------------------------------------------------------------------------
/Materials/UIInverseMask-Content.mat.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 06f7a8df89e0df844858e626bf84b508
3 | NativeFormatImporter:
4 | externalObjects: {}
5 | mainObjectFileID: 0
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Materials/UIInverseMask-Cutout.mat:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!21 &2100000
4 | Material:
5 | serializedVersion: 6
6 | m_ObjectHideFlags: 0
7 | m_CorrespondingSourceObject: {fileID: 0}
8 | m_PrefabInstance: {fileID: 0}
9 | m_PrefabAsset: {fileID: 0}
10 | m_Name: UIInverseMask-Cutout
11 | m_Shader: {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0}
12 | m_ShaderKeywords: ETC1_EXTERNAL_ALPHA UNITY_UI_ALPHACLIP
13 | m_LightmapFlags: 4
14 | m_EnableInstancingVariants: 0
15 | m_DoubleSidedGI: 0
16 | m_CustomRenderQueue: -1
17 | stringTagMap: {}
18 | disabledShaderPasses: []
19 | m_SavedProperties:
20 | serializedVersion: 3
21 | m_TexEnvs:
22 | - _BumpMap:
23 | m_Texture: {fileID: 0}
24 | m_Scale: {x: 1, y: 1}
25 | m_Offset: {x: 0, y: 0}
26 | - _DetailAlbedoMap:
27 | m_Texture: {fileID: 0}
28 | m_Scale: {x: 1, y: 1}
29 | m_Offset: {x: 0, y: 0}
30 | - _DetailMask:
31 | m_Texture: {fileID: 0}
32 | m_Scale: {x: 1, y: 1}
33 | m_Offset: {x: 0, y: 0}
34 | - _DetailNormalMap:
35 | m_Texture: {fileID: 0}
36 | m_Scale: {x: 1, y: 1}
37 | m_Offset: {x: 0, y: 0}
38 | - _EmissionMap:
39 | m_Texture: {fileID: 0}
40 | m_Scale: {x: 1, y: 1}
41 | m_Offset: {x: 0, y: 0}
42 | - _MainTex:
43 | m_Texture: {fileID: 0}
44 | m_Scale: {x: 1, y: 1}
45 | m_Offset: {x: 0, y: 0}
46 | - _MetallicGlossMap:
47 | m_Texture: {fileID: 0}
48 | m_Scale: {x: 1, y: 1}
49 | m_Offset: {x: 0, y: 0}
50 | - _OcclusionMap:
51 | m_Texture: {fileID: 0}
52 | m_Scale: {x: 1, y: 1}
53 | m_Offset: {x: 0, y: 0}
54 | - _ParallaxMap:
55 | m_Texture: {fileID: 0}
56 | m_Scale: {x: 1, y: 1}
57 | m_Offset: {x: 0, y: 0}
58 | m_Floats:
59 | - _BumpScale: 1
60 | - _ColorMask: 0
61 | - _Cutoff: 0.5
62 | - _DetailNormalMapScale: 1
63 | - _DstBlend: 0
64 | - _GlossMapScale: 1
65 | - _Glossiness: 0.5
66 | - _GlossyReflections: 1
67 | - _Metallic: 0
68 | - _Mode: 0
69 | - _OcclusionStrength: 1
70 | - _Parallax: 0.02
71 | - _SmoothnessTextureChannel: 0
72 | - _SpecularHighlights: 1
73 | - _SrcBlend: 1
74 | - _Stencil: 1
75 | - _StencilComp: 8
76 | - _StencilOp: 2
77 | - _StencilReadMask: 255
78 | - _StencilWriteMask: 255
79 | - _UVSec: 0
80 | - _UseUIAlphaClip: 1
81 | - _ZWrite: 1
82 | m_Colors:
83 | - _Color: {r: 1, g: 1, b: 1, a: 1}
84 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
85 |
--------------------------------------------------------------------------------
/Materials/UIInverseMask-Cutout.mat.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: efee781990b78934a9de5ffb9cf227b5
3 | NativeFormatImporter:
4 | externalObjects: {}
5 | mainObjectFileID: 0
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UI Toolkit
2 |
3 | [](https://github.com/zigurous/unity-ui-toolkit) [](https://github.com/zigurous/unity-ui-toolkit/releases) [](https://docs.zigurous.com/com.zigurous.ui) [](https://github.com/zigurous/unity-ui-toolkit/blob/main/LICENSE.md)
4 |
5 | The **UI Toolkit** package contains scripts and utilities for creating UI in Unity projects. The package is intended to solve common problems that arise when developing UI and menus. The package is still early in development, and more functionality will be added over time.
6 |
7 | ## Reference
8 |
9 | - [Menu Tools](https://docs.zigurous.com/com.zigurous.ui/manual/menus)
10 | - [Letterboxing](https://docs.zigurous.com/com.zigurous.ui/manual/letterboxing)
11 | - [Screen Size](https://docs.zigurous.com/com.zigurous.ui/manual/screen-size)
12 |
13 | ## Installation
14 |
15 | Use the Unity [Package Manager](https://docs.unity3d.com/Manual/upm-ui.html) to install the **UI Toolkit** package.
16 |
17 | 1. Open the Package Manager in `Window > Package Manager`
18 | 2. Click the add (`+`) button in the status bar
19 | 3. Select `Add package from git URL` from the add menu
20 | 4. Enter the following Git URL in the text box and click Add:
21 |
22 | ```
23 | https://github.com/zigurous/unity-ui-toolkit.git
24 | ```
25 |
26 | ## Namespace
27 |
28 | Import the package namespace in each script or file you want to use it. You may need to regenerate project files/assemblies first.
29 |
30 | ```csharp
31 | using Zigurous.UI;
32 | ```
33 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c4d1ecb5625053e4b84282a4cc466f1d
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 96ade485c057e754ba4d03a59fd0c7ed
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/CinematicBars.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using UnityEngine;
3 | using UnityEngine.UI;
4 |
5 | namespace Zigurous.UI
6 | {
7 | ///
8 | /// Displays mattes on the top and bottom of the screen to crop the screen
9 | /// to a specified aspect ratio. This is also referred to as letterboxing
10 | /// and is useful for cutscenes.
11 | ///
12 | [RequireComponent(typeof(RectTransform))]
13 | [AddComponentMenu("Zigurous/UI/Misc/Cinematic Bars")]
14 | public sealed class CinematicBars : MonoBehaviour
15 | {
16 | [SerializeField]
17 | [Tooltip("The color of the mattes.")]
18 | private Color m_Color = Color.black;
19 |
20 | [SerializeField]
21 | [Tooltip("The material of the mattes.")]
22 | private Material m_Material = null;
23 |
24 | [SerializeField]
25 | [Tooltip("The aspect ratio of the mattes.")]
26 | private float m_AspectRatio = 2.35f;
27 |
28 | [SerializeField]
29 | [Tooltip("The amount of seconds it takes to animate the mattes.")]
30 | private float m_AnimationDuration = 0.5f;
31 |
32 | ///
33 | /// The top letterbox matte (Read only).
34 | ///
35 | public RectTransform matteTop { get; private set; }
36 |
37 | ///
38 | /// The bottom letterbox matte (Read only).
39 | ///
40 | public RectTransform matteBottom { get; private set; }
41 |
42 | ///
43 | /// The current height of the letterbox mattes (Read only).
44 | ///
45 | public float matteHeight { get; private set; }
46 |
47 | ///
48 | /// The color of the mattes.
49 | ///
50 | public Color color
51 | {
52 | get => m_Color;
53 | set { m_Color = value; UpdateStyles(); }
54 | }
55 |
56 | ///
57 | /// The material of the mattes.
58 | ///
59 | public Material material
60 | {
61 | get => m_Material;
62 | set { m_Material = value; UpdateStyles(); }
63 | }
64 |
65 | ///
66 | /// The aspect ratio of the mattes.
67 | ///
68 | public float aspectRatio
69 | {
70 | get => m_AspectRatio;
71 | set { m_AspectRatio = value; UpdateMattes(); }
72 | }
73 |
74 | ///
75 | /// The amount of seconds it takes to animate the mattes.
76 | ///
77 | public float animationDuration
78 | {
79 | get => m_AnimationDuration;
80 | set => m_AnimationDuration = value;
81 | }
82 |
83 | ///
84 | /// The coroutine that animates the mattes.
85 | ///
86 | private Coroutine coroutine;
87 |
88 | #if UNITY_EDITOR
89 | private bool invalidated;
90 | #endif
91 |
92 | private void Awake()
93 | {
94 | StretchToScreenSize stretch = gameObject.AddComponent();
95 | stretch.hideFlags = HideFlags.HideInInspector;
96 | stretch.stretchWidth = true;
97 | stretch.stretchHeight = true;
98 |
99 | matteBottom = CreateMatte();
100 | matteTop = CreateMatte();
101 | matteTop.localScale = new Vector3(1f, -1f, 1f);
102 |
103 | SetDesiredHeight(0f);
104 | }
105 |
106 | private RectTransform CreateMatte()
107 | {
108 | GameObject matte = new GameObject("Matte");
109 | matte.transform.parent = transform;
110 |
111 | RectTransform matteRect = matte.AddComponent();
112 | matteRect.SetHeight(0f);
113 |
114 | matte.AddComponent();
115 |
116 | Image graphic = matte.AddComponent();
117 | graphic.color = color;
118 | graphic.material = material;
119 |
120 | StretchToScreenSize stretch = matte.AddComponent();
121 | stretch.stretchWidth = true;
122 | stretch.stretchHeight = false;
123 |
124 | return matteRect;
125 | }
126 |
127 | private void Start()
128 | {
129 | ScreenSizeListener.Instance.resized += OnScreenResize;
130 | }
131 |
132 | private void OnDestroy()
133 | {
134 | if (ScreenSizeListener.HasInstance) {
135 | ScreenSizeListener.Instance.resized -= OnScreenResize;
136 | }
137 | }
138 |
139 | #if UNITY_EDITOR
140 | private void OnValidate()
141 | {
142 | invalidated = true;
143 | }
144 | #endif
145 |
146 | private void OnEnable()
147 | {
148 | UpdateMattes();
149 | }
150 |
151 | private void OnDisable()
152 | {
153 | UpdateMattes();
154 | }
155 |
156 | private void OnScreenResize(int width, int height)
157 | {
158 | UpdateMattes(animated: false);
159 | }
160 |
161 | #if UNITY_EDITOR
162 | private void Update()
163 | {
164 | if (invalidated)
165 | {
166 | UpdateStyles();
167 | UpdateMattes(animated: false);
168 |
169 | invalidated = false;
170 | }
171 | }
172 | #endif
173 |
174 | private void UpdateMattes()
175 | {
176 | UpdateMattes(animated: animationDuration > 0f);
177 | }
178 |
179 | private void UpdateMattes(bool animated)
180 | {
181 | if (!gameObject.activeInHierarchy)
182 | {
183 | SetDesiredHeight(0f);
184 | return;
185 | }
186 |
187 | float desiredHeight = CalculateMatteHeight();
188 |
189 | if (animated)
190 | {
191 | if (coroutine != null) {
192 | StopCoroutine(coroutine);
193 | }
194 |
195 | coroutine = StartCoroutine(Animate(matteHeight, desiredHeight));
196 | }
197 | else
198 | {
199 | SetDesiredHeight(desiredHeight);
200 | }
201 | }
202 |
203 | private IEnumerator Animate(float currentHeight, float desiredHeight)
204 | {
205 | float elapsed = 0f;
206 |
207 | while (elapsed < animationDuration)
208 | {
209 | float percent = Mathf.Clamp01(elapsed / animationDuration);
210 | float height = Mathf.SmoothStep(currentHeight, desiredHeight, percent);
211 |
212 | SetDesiredHeight(height);
213 |
214 | elapsed += Time.deltaTime;
215 | yield return null;
216 | }
217 |
218 | SetDesiredHeight(desiredHeight);
219 |
220 | coroutine = null;
221 | }
222 |
223 | private float CalculateMatteHeight()
224 | {
225 | if (!enabled) {
226 | return 0f;
227 | }
228 |
229 | float screenWidth = Screen.width;
230 | float screenHeight = Screen.height;
231 |
232 | // Screen.width and Screen.height oddly does not always give the
233 | // correct values so try to use ScreenSizeListener if available
234 | if (ScreenSizeListener.HasInstance)
235 | {
236 | screenWidth = ScreenSizeListener.Instance.width;
237 | screenHeight = ScreenSizeListener.Instance.height;
238 | }
239 |
240 | float letterbox = screenWidth / aspectRatio;
241 | float height = (screenHeight - letterbox) / 2f;
242 |
243 | return float.IsNaN(height) ? 0f : height;
244 | }
245 |
246 | private void SetDesiredHeight(float height)
247 | {
248 | matteHeight = height;
249 |
250 | if (matteTop != null) {
251 | matteTop.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0f, height);
252 | }
253 |
254 | if (matteBottom != null) {
255 | matteBottom.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, 0f, height);
256 | }
257 | }
258 |
259 | private void UpdateStyles()
260 | {
261 | if (matteTop != null)
262 | {
263 | Graphic graphic = matteTop.GetComponent();
264 | graphic.color = color;
265 | graphic.material = material;
266 | }
267 |
268 | if (matteBottom != null)
269 | {
270 | Graphic graphic = matteBottom.GetComponent();
271 | graphic.color = color;
272 | graphic.material = material;
273 | }
274 | }
275 |
276 | }
277 |
278 | }
279 |
--------------------------------------------------------------------------------
/Runtime/CinematicBars.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: edd698e7de211f94190a6d2108bd18c1
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5ed78365befa494498137b3b97bdd0f6
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/Extensions/CanvasExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEngine.UI;
3 |
4 | namespace Zigurous.UI
5 | {
6 | ///
7 | /// Extension methods for UI canvas.
8 | ///
9 | public static class CanvasExtensions
10 | {
11 | ///
12 | /// Fades the alpha of all graphics of the canvas to 100% over the given
13 | /// duration.
14 | ///
15 | /// The canvas to fade.
16 | /// The amount of seconds it takes to fade the graphics.
17 | /// Ignores the time scale when fading the graphics.
18 | public static void FadeInGraphics(this Canvas canvas, float duration, bool ignoreTimeScale = false)
19 | {
20 | Graphic[] graphics = canvas.GetComponentsInChildren();
21 |
22 | for (int i = 0; i < graphics.Length; i++) {
23 | graphics[i].CrossFadeAlpha(1f, duration, ignoreTimeScale);
24 | }
25 | }
26 |
27 | ///
28 | /// Fades the alpha of all graphics of the canvas to 0% over the given
29 | /// duration.
30 | ///
31 | /// The canvas to fade.
32 | /// The amount of seconds it takes to fade the graphics.
33 | /// Ignores the time scale when fading the graphics.
34 | public static void FadeOutGraphics(this Canvas canvas, float duration, bool ignoreTimeScale = false)
35 | {
36 | Graphic[] graphics = canvas.GetComponentsInChildren();
37 |
38 | for (int i = 0; i < graphics.Length; i++) {
39 | graphics[i].CrossFadeAlpha(0f, duration, ignoreTimeScale);
40 | }
41 | }
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/Runtime/Extensions/CanvasExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f24822dad860ee64fbaaa32076539d38
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Extensions/GraphicExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine.UI;
2 |
3 | namespace Zigurous.UI
4 | {
5 | ///
6 | /// Extension methods for UI graphics.
7 | ///
8 | public static class GraphicExtensions
9 | {
10 | ///
11 | /// Fades the alpha of the graphic to 100% over the given duration.
12 | ///
13 | /// The graphic to fade.
14 | /// The amount of seconds it takes to fade the graphic.
15 | /// Ignores the time scale when fading the graphic.
16 | public static void FadeIn(this Graphic graphic, float duration, bool ignoreTimeScale = false)
17 | {
18 | graphic.CrossFadeAlpha(1f, duration, ignoreTimeScale);
19 | }
20 |
21 | ///
22 | /// Fades the alpha of the graphic to 0% over the given duration.
23 | ///
24 | /// The graphic to fade.
25 | /// The amount of seconds it takes to fade the graphic.
26 | /// Ignores the time scale when fading the graphic.
27 | public static void FadeOut(this Graphic graphic, float duration, bool ignoreTimeScale = false)
28 | {
29 | graphic.CrossFadeAlpha(0f, duration, ignoreTimeScale);
30 | }
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Runtime/Extensions/GraphicExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3fbff746fbe88e74183bc62297d544fd
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Extensions/RectTransformExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Zigurous.UI
4 | {
5 | ///
6 | /// Extension methods for RectTransform.
7 | ///
8 | public static class RectTransformExtensions
9 | {
10 | private static Vector3[] corners = new Vector3[4];
11 |
12 | ///
13 | /// Calculates the world-space rect of the transform.
14 | ///
15 | /// The transform to calculate the world rect of.
16 | /// Ignores the scale of the transform when setting the rect size (default=false).
17 | /// The world rect of the transform.
18 | public static Rect GetWorldRect(this RectTransform transform, bool ignoreScale = false)
19 | {
20 | transform.GetWorldCorners(corners);
21 |
22 | Vector3 topLeft = corners[0];
23 | Vector3 size = transform.rect.size;
24 |
25 | if (!ignoreScale) {
26 | size.Scale(transform.lossyScale);
27 | }
28 |
29 | return new Rect(topLeft, size);
30 | }
31 |
32 | ///
33 | /// Sets the width of the rect transform to the given value.
34 | ///
35 | /// The rect transform to update.
36 | /// The width value to set.
37 | public static void SetWidth(this RectTransform rect, float width) =>
38 | rect.sizeDelta = new Vector2(width, rect.sizeDelta.y);
39 |
40 | ///
41 | /// Sets the height of the rect transform to the given value.
42 | ///
43 | /// The rect transform to update.
44 | /// The height value to set.
45 | public static void SetHeight(this RectTransform rect, float height) =>
46 | rect.sizeDelta = new Vector2(rect.sizeDelta.x, height);
47 |
48 | ///
49 | /// Sets the left offset of the rect transform to the given value.
50 | ///
51 | /// The rect transform to update.
52 | /// The left offset value to set.
53 | public static void SetLeft(this RectTransform rect, float left) =>
54 | rect.offsetMin = new Vector2(left, rect.offsetMin.y);
55 |
56 | ///
57 | /// Sets the right offset of the rect transform to the given value.
58 | ///
59 | /// The rect transform to update.
60 | /// The right offset value to set.
61 | public static void SetRight(this RectTransform rect, float right) =>
62 | rect.offsetMax = new Vector2(-right, rect.offsetMax.y);
63 |
64 | ///
65 | /// Sets the top offset of the rect transform to the given value.
66 | ///
67 | /// The rect transform to update.
68 | /// The top offset value to set.
69 | public static void SetTop(this RectTransform rect, float top) =>
70 | rect.offsetMax = new Vector2(rect.offsetMax.x, -top);
71 |
72 | ///
73 | /// Sets the bottom offset of the rect transform to the given value.
74 | ///
75 | /// The rect transform to update.
76 | /// The bottom offset value to set.
77 | public static void SetBottom(this RectTransform rect, float bottom) =>
78 | rect.offsetMin = new Vector2(rect.offsetMin.x, bottom);
79 |
80 | ///
81 | /// Sets the left anchor of the rect transform to the given value.
82 | ///
83 | /// The rect transform to update.
84 | /// The left anchor value to set.
85 | public static void SetAnchorMinX(this RectTransform rect, float minX) =>
86 | rect.anchorMin = new Vector2(minX, rect.anchorMin.y);
87 |
88 | ///
89 | /// Sets the bottom anchor of the rect transform to the given value.
90 | ///
91 | /// The rect transform to update.
92 | /// The bottom anchor value to set.
93 | public static void SetAnchorMinY(this RectTransform rect, float minY) =>
94 | rect.anchorMin = new Vector2(rect.anchorMin.x, minY);
95 |
96 | ///
97 | /// Sets the right anchor of the rect transform to the given value.
98 | ///
99 | /// The rect transform to update.
100 | /// The right anchor value to set.
101 | public static void SetAnchorMaxX(this RectTransform rect, float maxX) =>
102 | rect.anchorMax = new Vector2(maxX, rect.anchorMax.y);
103 |
104 | ///
105 | /// Sets the top anchor of the rect transform to the given value.
106 | ///
107 | /// The rect transform to update.
108 | /// The top anchor value to set.
109 | public static void SetAnchorMaxY(this RectTransform rect, float maxY) =>
110 | rect.anchorMax = new Vector2(rect.anchorMax.x, maxY);
111 |
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/Runtime/Extensions/RectTransformExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 548c76697311bea478208a1bf002e25f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/InverseMask.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEngine.UI;
3 |
4 | namespace Zigurous.UI
5 | {
6 | ///
7 | /// Applies materials to the image and its children to create an
8 | /// inverse mask.
9 | ///
10 | [ExecuteAlways]
11 | [RequireComponent(typeof(Image))]
12 | [AddComponentMenu("Zigurous/UI/Effects/Inverse Mask")]
13 | public sealed class InverseMask : MonoBehaviour
14 | {
15 | private static Material m_CutoutMaterial;
16 | private static Material m_ContentMaterial;
17 |
18 | ///
19 | /// The shared material applied to an image that is masking another
20 | /// image. This image acts as a cutout, thus its contents are not visible.
21 | ///
22 | public static Material cutoutMaterial
23 | {
24 | get
25 | {
26 | if (m_CutoutMaterial == null)
27 | {
28 | m_CutoutMaterial = new Material(Shader.Find("UI/Default"));
29 | m_CutoutMaterial.name = "UIInverseMask-Cutout";
30 | m_CutoutMaterial.color = new Color(1f, 1f, 1f, 1f / 256f);
31 | m_CutoutMaterial.shaderKeywords = new string[] { "UNITY_UI_ALPHACLIP" };
32 | m_CutoutMaterial.SetInt("_Stencil", 1);
33 | m_CutoutMaterial.SetInt("_StencilComp", 8);
34 | m_CutoutMaterial.SetInt("_StencilOp", 2);
35 | m_CutoutMaterial.SetInt("_StencilWriteMask", 255);
36 | m_CutoutMaterial.SetInt("_StencilReadMask", 255);
37 | m_CutoutMaterial.SetInt("_ColorMask", 0);
38 | m_CutoutMaterial.SetInt("_UseUIAlphaClip", 1);
39 | }
40 |
41 | return m_CutoutMaterial;
42 | }
43 | }
44 |
45 | ///
46 | /// The shared material applied to the children images being masked.
47 | /// The content of these images will be visible in the shape of the
48 | /// parent cutout mask.
49 | ///
50 | public static Material contentMaterial
51 | {
52 | get
53 | {
54 | if (m_ContentMaterial == null)
55 | {
56 | m_ContentMaterial = new Material(Shader.Find("UI/Default"));
57 | m_ContentMaterial.name = "UIInverseMask-Content";
58 | m_ContentMaterial.color = Color.white;
59 | m_ContentMaterial.SetInt("_Stencil", 2);
60 | m_ContentMaterial.SetInt("_StencilComp", 3);
61 | m_ContentMaterial.SetInt("_StencilOp", 0);
62 | m_ContentMaterial.SetInt("_StencilWriteMask", 0);
63 | m_ContentMaterial.SetInt("_StencilReadMask", 1);
64 | m_ContentMaterial.SetInt("_ColorMask", 15);
65 | m_ContentMaterial.SetInt("_UseUIAlphaClip", 0);
66 | }
67 |
68 | return m_ContentMaterial;
69 | }
70 | }
71 |
72 | #if UNITY_EDITOR
73 | private bool invalidated;
74 |
75 | private void OnValidate()
76 | {
77 | invalidated = true;
78 | }
79 |
80 | private void Update()
81 | {
82 | if (invalidated)
83 | {
84 | Apply();
85 | invalidated = false;
86 | }
87 | }
88 | #endif
89 |
90 | private void OnEnable()
91 | {
92 | Apply();
93 | }
94 |
95 | private void OnDisable()
96 | {
97 | Remove();
98 | }
99 |
100 | private void Apply()
101 | {
102 | Image mask = GetComponent();
103 | mask.material = InverseMask.cutoutMaterial;
104 |
105 | Image[] images = GetComponentsInChildren();
106 | for (int i = 0; i < images.Length; i++)
107 | {
108 | Image image = images[i];
109 |
110 | if (image.transform != transform) {
111 | image.material = InverseMask.contentMaterial;
112 | }
113 | }
114 | }
115 |
116 | private void Remove()
117 | {
118 | Image mask = GetComponent();
119 | mask.material = null;
120 |
121 | Image[] images = GetComponentsInChildren();
122 | for (int i = 0; i < images.Length; i++)
123 | {
124 | Image image = images[i];
125 |
126 | if (image.transform != transform) {
127 | image.material = null;
128 | }
129 | }
130 | }
131 |
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/Runtime/InverseMask.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4788d26ccf600544c9843b994e5c2bd5
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Letterboxing.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using UnityEngine;
3 |
4 | namespace Zigurous.UI
5 | {
6 | ///
7 | /// Crops the screen to a specified aspect ratio by changing the camera's
8 | /// viewport. This is known as letterboxing and is useful for cutscenes.
9 | ///
10 | [RequireComponent(typeof(Camera))]
11 | [AddComponentMenu("Zigurous/UI/Misc/Letterboxing")]
12 | public sealed class Letterboxing : MonoBehaviour
13 | {
14 | [SerializeField]
15 | [Tooltip("The aspect ratio of the mattes.")]
16 | private float m_AspectRatio = 2.35f;
17 |
18 | [SerializeField]
19 | [Tooltip("The amount of seconds it takes to animate the mattes.")]
20 | private float m_AnimationDuration = 0.5f;
21 |
22 | ///
23 | /// The camera being letterboxed (Read only).
24 | ///
25 | public new Camera camera { get; private set; }
26 |
27 | ///
28 | /// The current height of the viewport (Read only).
29 | ///
30 | public float viewportHeight => camera.rect.height;
31 |
32 | ///
33 | /// The aspect ratio of the mattes.
34 | ///
35 | public float aspectRatio
36 | {
37 | get => m_AspectRatio;
38 | set { m_AspectRatio = value; UpdateViewport(); }
39 | }
40 |
41 | ///
42 | /// The amount of seconds it takes to animate the mattes.
43 | ///
44 | public float animationDuration
45 | {
46 | get => m_AnimationDuration;
47 | set => m_AnimationDuration = value;
48 | }
49 |
50 | ///
51 | /// The coroutine that animates the mattes.
52 | ///
53 | private Coroutine coroutine;
54 |
55 | #if UNITY_EDITOR
56 | private bool invalidated;
57 | #endif
58 |
59 | private void Awake()
60 | {
61 | camera = GetComponent();
62 | }
63 |
64 | private void Start()
65 | {
66 | ScreenSizeListener.Instance.resized += OnScreenResize;
67 | }
68 |
69 | private void OnDestroy()
70 | {
71 | if (ScreenSizeListener.HasInstance) {
72 | ScreenSizeListener.Instance.resized -= OnScreenResize;
73 | }
74 | }
75 |
76 | #if UNITY_EDITOR
77 | private void OnValidate()
78 | {
79 | invalidated = true;
80 | }
81 | #endif
82 |
83 | private void OnEnable()
84 | {
85 | UpdateViewport();
86 | }
87 |
88 | private void OnDisable()
89 | {
90 | UpdateViewport();
91 | }
92 |
93 | private void OnScreenResize(int width, int height)
94 | {
95 | UpdateViewport(animated: false);
96 | }
97 |
98 | #if UNITY_EDITOR
99 | private void Update()
100 | {
101 | if (invalidated)
102 | {
103 | UpdateViewport(animated: false);
104 |
105 | invalidated = false;
106 | }
107 | }
108 | #endif
109 |
110 | private void UpdateViewport()
111 | {
112 | UpdateViewport(animated: animationDuration > 0f);
113 | }
114 |
115 | private void UpdateViewport(bool animated)
116 | {
117 | if (!gameObject.activeInHierarchy)
118 | {
119 | SetViewportHeight(1f);
120 | return;
121 | }
122 |
123 | float desiredHeight = CalculateViewportHeight();
124 |
125 | if (animated)
126 | {
127 | if (coroutine != null) {
128 | StopCoroutine(coroutine);
129 | }
130 |
131 | coroutine = StartCoroutine(Animate(viewportHeight, desiredHeight));
132 | }
133 | else
134 | {
135 | SetViewportHeight(desiredHeight);
136 | }
137 | }
138 |
139 | private IEnumerator Animate(float currentHeight, float desiredHeight)
140 | {
141 | float elapsed = 0f;
142 |
143 | while (elapsed < animationDuration)
144 | {
145 | float percent = Mathf.Clamp01(elapsed / animationDuration);
146 | float height = Mathf.SmoothStep(currentHeight, desiredHeight, percent);
147 |
148 | SetViewportHeight(height);
149 |
150 | elapsed += Time.deltaTime;
151 | yield return null;
152 | }
153 |
154 | SetViewportHeight(desiredHeight);
155 |
156 | coroutine = null;
157 | }
158 |
159 | private float CalculateViewportHeight()
160 | {
161 | if (!enabled) {
162 | return 1f;
163 | }
164 |
165 | float screenWidth = Screen.width;
166 | float screenHeight = Screen.height;
167 |
168 | // Screen.width and Screen.height oddly does not always give the
169 | // correct values so try to use ScreenSizeListener if available
170 | if (ScreenSizeListener.HasInstance)
171 | {
172 | screenWidth = ScreenSizeListener.Instance.width;
173 | screenHeight = ScreenSizeListener.Instance.height;
174 | }
175 |
176 | float letterbox = screenWidth / aspectRatio;
177 | float height = (screenHeight - letterbox) / 2f;
178 | float viewport = 1f - ((height / screenHeight) * 2f);
179 |
180 | return float.IsNaN(viewport) ? 1f : viewport;
181 | }
182 |
183 | private void SetViewportHeight(float height)
184 | {
185 | Rect rect = camera.rect;
186 | rect.height = height;
187 | rect.y = (1f - height) / 2f;
188 |
189 | camera.rect = rect;
190 | }
191 |
192 | }
193 |
194 | }
195 |
--------------------------------------------------------------------------------
/Runtime/Letterboxing.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 843d186670a1d034ab44841facabc66f
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/NavigationStack.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 | using UnityEngine.EventSystems;
4 | #if ENABLE_INPUT_SYSTEM
5 | using UnityEngine.InputSystem;
6 | #endif
7 |
8 | namespace Zigurous.UI
9 | {
10 | ///
11 | /// Manages a stack of game objects for menu navigation purposes. This is
12 | /// especially useful to handle backwards navigation by simply popping off
13 | /// the last item in the stack.
14 | ///
15 | [RequireComponent(typeof(EventSystem))]
16 | [AddComponentMenu("Zigurous/UI/Navigation/Navigation Stack")]
17 | public class NavigationStack : MonoBehaviour
18 | {
19 | ///
20 | /// The event system being tracked by the navigation stack (Read only).
21 | ///
22 | public EventSystem eventSystem { get; private set; }
23 |
24 | ///
25 | /// The game objects added to the stack (Read only).
26 | ///
27 | public Stack items { get; private set; }
28 |
29 | ///
30 | /// The current selected game object at the top of the stack (Read only).
31 | ///
32 | public GameObject top => items.Count > 0 ? items.Peek() : null;
33 |
34 | #if ENABLE_INPUT_SYSTEM
35 | ///
36 | /// The input action that handles backwards navigation by popping items
37 | /// off the stack.
38 | ///
39 | [Tooltip("The input action that handles backwards navigation by popping items off the stack.")]
40 | public InputAction backNavigationInput = new InputAction("MenuBackNavigation", InputActionType.Button);
41 | #endif
42 |
43 | #if ENABLE_LEGACY_INPUT_MANAGER
44 | ///
45 | /// The input button that handles backwards navigation by popping items
46 | /// off the stack.
47 | ///
48 | [Tooltip("The input button that handles backwards navigation by popping items off the stack.")]
49 | public string legacyBackNavigationInput = "Cancel";
50 | #endif
51 |
52 | ///
53 | /// The root game object added to the bottom of the stack.
54 | ///
55 | [Tooltip("The root game object added to the bottom of the stack.")]
56 | public GameObject rootGameObject;
57 |
58 | ///
59 | /// Automatically sets the active state of game objects as they are
60 | /// pushed on and off the stack.
61 | ///
62 | [Tooltip("Automatically sets the active state of game objects as they are pushed on and off the stack.")]
63 | public bool setActiveState = true;
64 |
65 | ///
66 | /// Allows for all items to be popped off the stack. Often times you
67 | /// want to maintain at least the root game object.
68 | ///
69 | [Tooltip("Allows for all items to be popped off the stack. Often times you want to maintain at least the root game object.")]
70 | public bool allowEmptyStack = false;
71 |
72 | ///
73 | /// Allows for null game objects to be pushed onto the stack.
74 | ///
75 | [Tooltip("Allows for null game objects to be pushed onto the stack.")]
76 | public bool allowNullSelections = false;
77 |
78 | #if ENABLE_INPUT_SYSTEM
79 | private void Reset()
80 | {
81 | backNavigationInput = new InputAction("MenuBackNavigation", InputActionType.Button);
82 | backNavigationInput.AddBinding("/escape");
83 | backNavigationInput.AddBinding("/backspace");
84 | backNavigationInput.AddBinding("/select");
85 | backNavigationInput.AddBinding("/buttonEast");
86 | }
87 | #endif
88 |
89 | private void Awake()
90 | {
91 | items = new Stack(8);
92 | eventSystem = GetComponent();
93 |
94 | #if ENABLE_INPUT_SYSTEM
95 | backNavigationInput.performed += OnBack;
96 | #endif
97 | }
98 |
99 | private void Start()
100 | {
101 | Push(rootGameObject);
102 | }
103 |
104 | #if ENABLE_INPUT_SYSTEM
105 | private void OnEnable()
106 | {
107 | backNavigationInput.Enable();
108 | }
109 |
110 | private void OnDisable()
111 | {
112 | backNavigationInput.Disable();
113 | }
114 | #endif
115 |
116 | #if ENABLE_LEGACY_INPUT_MANAGER
117 | private void Update()
118 | {
119 | try
120 | {
121 | if (!string.IsNullOrEmpty(legacyBackNavigationInput) && Input.GetButtonDown(legacyBackNavigationInput)) {
122 | Pop();
123 | }
124 | }
125 | catch
126 | {
127 | #if UNITY_EDITOR || DEVELOPMENT_BUILD
128 | Debug.LogWarning($"[NavigationStack] Input button '{legacyBackNavigationInput}' is not setup.\nDefine the input in the Input Manager settings accessed from the menu: Edit > Project Settings");
129 | #endif
130 | }
131 | }
132 | #endif
133 |
134 | ///
135 | /// Pushes a game object onto the stack, effectively navigating
136 | /// forwards.
137 | ///
138 | /// The game object to push onto the stack.
139 | public void Push(GameObject selected)
140 | {
141 | if (selected != null || allowNullSelections)
142 | {
143 | if (setActiveState && selected != null) {
144 | selected.SetActive(true);
145 | }
146 |
147 | eventSystem.SetSelectedGameObject(selected);
148 | items.Push(selected);
149 | }
150 | }
151 |
152 | ///
153 | /// Pops the last game object off the stack, effectively navigating
154 | /// backwards.
155 | ///
156 | /// The game object that was popped off the stack.
157 | public GameObject Pop()
158 | {
159 | if (items.Count == 0) {
160 | return null;
161 | }
162 |
163 | GameObject top = null;
164 |
165 | // Pop off the top of the stack
166 | if (items.Count > 1 || allowEmptyStack)
167 | {
168 | top = items.Pop();
169 |
170 | if (setActiveState && top != null) {
171 | top.SetActive(false);
172 | }
173 |
174 | eventSystem.SetSelectedGameObject(null);
175 | }
176 |
177 | // Set the previous item to be active
178 | if (items.Count > 0)
179 | {
180 | GameObject previous = items.Peek();
181 |
182 | if (setActiveState && previous != null) {
183 | previous.SetActive(true);
184 | }
185 |
186 | eventSystem.SetSelectedGameObject(previous);
187 | }
188 |
189 | return top;
190 | }
191 |
192 | #if ENABLE_INPUT_SYSTEM
193 | private void OnBack(InputAction.CallbackContext context)
194 | {
195 | if (context.performed) {
196 | Pop();
197 | }
198 | }
199 | #endif
200 |
201 | }
202 |
203 | }
204 |
--------------------------------------------------------------------------------
/Runtime/NavigationStack.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6f6342acb6c2cc54eab471d9e3b94c60
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ScreenSizeListener.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Zigurous.UI
4 | {
5 | ///
6 | /// Listens for changes in the screen size.
7 | ///
8 | [AddComponentMenu("")]
9 | public sealed class ScreenSizeListener : MonoBehaviour
10 | {
11 | private static volatile ScreenSizeListener instance;
12 | private static object lockObject = new object();
13 | private static bool isUnloading = false;
14 |
15 | ///
16 | /// The current instance of the class. The instance will be created if
17 | /// it does not already exist.
18 | ///
19 | /// The instance of the class.
20 | public static ScreenSizeListener Instance
21 | {
22 | get
23 | {
24 | if (isUnloading) {
25 | return null;
26 | }
27 |
28 | if (instance == null)
29 | {
30 | lock (lockObject)
31 | {
32 | instance = FindObjectOfType();
33 |
34 | if (instance == null)
35 | {
36 | GameObject singleton = new GameObject();
37 | singleton.name = typeof(ScreenSizeListener).Name;
38 | singleton.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
39 | singleton.AddComponent();
40 | DontDestroyOnLoad(singleton);
41 | }
42 | }
43 | }
44 |
45 | return instance;
46 | }
47 | }
48 |
49 | ///
50 | /// Checks if the singleton has been initialized and an instance is
51 | /// available to use.
52 | ///
53 | /// True if an instance is available, false otherwise.
54 | public static bool HasInstance => instance != null;
55 |
56 | ///
57 | /// A function delegate invoked when the screen size changes.
58 | ///
59 | /// The new width of the screen.
60 | /// The new height of the screen.
61 | public delegate void OnResize(int width, int height);
62 |
63 | ///
64 | /// A callback invoked when the screen size changes.
65 | ///
66 | public OnResize resized;
67 |
68 | ///
69 | /// The current size of the screen (Read only).
70 | ///
71 | public Vector2Int size => new Vector2Int(width, height);
72 |
73 | ///
74 | /// The current width of the screen (Read only).
75 | ///
76 | public int width { get; private set; }
77 |
78 | ///
79 | /// The current height of the screen (Read only).
80 | ///
81 | public int height { get; private set; }
82 |
83 | private ScreenSizeListener() {}
84 |
85 | private void Awake()
86 | {
87 | isUnloading = false;
88 |
89 | if (instance == null)
90 | {
91 | instance = this;
92 |
93 | width = Screen.width;
94 | height = Screen.height;
95 | }
96 | else {
97 | Destroy(this);
98 | }
99 | }
100 |
101 | private void OnDestroy()
102 | {
103 | resized = null;
104 |
105 | isUnloading = true;
106 |
107 | if (instance == this) {
108 | instance = null;
109 | }
110 | }
111 |
112 | private void Update()
113 | {
114 | if (Screen.width != width || Screen.height != height)
115 | {
116 | width = Screen.width;
117 | height = Screen.height;
118 |
119 | if (resized != null) {
120 | resized.Invoke(width, height);
121 | }
122 | }
123 | }
124 |
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/Runtime/ScreenSizeListener.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3fa4a3d96d00bb74ebaa8ec68db725d8
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ScrollDirection.cs:
--------------------------------------------------------------------------------
1 | namespace Zigurous.UI
2 | {
3 | ///
4 | /// A scroll direction.
5 | ///
6 | public enum ScrollDirection
7 | {
8 | ///
9 | /// Scrolls in the y-axis.
10 | ///
11 | Vertical,
12 |
13 | ///
14 | /// Scrolls in the x-axis.
15 | ///
16 | Horizontal,
17 |
18 | ///
19 | /// Scrolls in both the x-axis and the y-axis.
20 | ///
21 | Both,
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/Runtime/ScrollDirection.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1c998d00f8614bd4c9d425e829eece23
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ScrollToSelection.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEngine.EventSystems;
3 | #if ENABLE_INPUT_SYSTEM
4 | using UnityEngine.InputSystem;
5 | #endif
6 | using UnityEngine.UI;
7 |
8 | namespace Zigurous.UI
9 | {
10 | ///
11 | /// Handles scrolling a ScrollRect component to the selected child element.
12 | /// This is especially useful for controller support.
13 | ///
14 | [RequireComponent(typeof(ScrollRect))]
15 | [AddComponentMenu("Zigurous/UI/Navigation/Scroll To Selection")]
16 | public class ScrollToSelection : MonoBehaviour
17 | {
18 | ///
19 | /// The ScrollRect component being scrolled (Read only).
20 | ///
21 | public ScrollRect scrollRect { get; private set; }
22 |
23 | ///
24 | /// The RectTransform component of the scroll rect (Read only).
25 | ///
26 | public RectTransform scrollTransform { get; private set; }
27 |
28 | ///
29 | /// The current selected game object (Read only).
30 | ///
31 | public GameObject selectedGameObject { get; private set; }
32 |
33 | ///
34 | /// The RectTransform of the current selected game object (Read only).
35 | ///
36 | public RectTransform selectedTransform { get; private set; }
37 |
38 | ///
39 | /// The direction to scroll the ScrollRect.
40 | ///
41 | [Tooltip("The direction to scroll the ScrollRect.")]
42 | public ScrollDirection scrollDirection = ScrollDirection.Vertical;
43 |
44 | ///
45 | /// How quickly the ScrollRect scrolls.
46 | ///
47 | [Tooltip("How quickly the ScrollRect scrolls.")]
48 | public float scrollSpeed = 10f;
49 |
50 | ///
51 | /// Whether the ScrollRect is currently being scrolled manually. This
52 | /// allows the user to freely scroll with the mouse even when a child
53 | /// element is selected (Read only).
54 | ///
55 | public bool manualScrolling { get; private set; }
56 |
57 | private void Awake()
58 | {
59 | scrollRect = GetComponent();
60 | scrollTransform = scrollRect.GetComponent();
61 | }
62 |
63 | private void Update()
64 | {
65 | CheckForManualScrolling();
66 | SetSelectedGameObject();
67 | SetScrollPosition();
68 | }
69 |
70 | private void CheckForManualScrolling()
71 | {
72 | #if ENABLE_INPUT_SYSTEM
73 | if (Mouse.current != null)
74 | {
75 | switch (scrollDirection)
76 | {
77 | case ScrollDirection.Horizontal:
78 | if (Mouse.current.scroll.x.IsActuated()) {
79 | manualScrolling = true;
80 | }
81 | break;
82 |
83 | case ScrollDirection.Vertical:
84 | if (Mouse.current.scroll.y.IsActuated()) {
85 | manualScrolling = true;
86 | }
87 | break;
88 |
89 | case ScrollDirection.Both:
90 | if (Mouse.current.scroll.x.IsActuated() || Mouse.current.scroll.y.IsActuated()) {
91 | manualScrolling = true;
92 | }
93 | break;
94 | }
95 | }
96 | #elif ENABLE_LEGACY_INPUT_MANAGER
97 | switch (scrollDirection)
98 | {
99 | case ScrollDirection.Horizontal:
100 | if (Input.mouseScrollDelta.x != 0f) {
101 | manualScrolling = true;
102 | }
103 | break;
104 |
105 | case ScrollDirection.Vertical:
106 | if (Input.mouseScrollDelta.y != 0f) {
107 | manualScrolling = true;
108 | }
109 | break;
110 |
111 | case ScrollDirection.Both:
112 | if (Input.mouseScrollDelta.x != 0f || Input.mouseScrollDelta.y != 0f) {
113 | manualScrolling = true;
114 | }
115 | break;
116 | }
117 | #endif
118 | }
119 |
120 | private void SetSelectedGameObject()
121 | {
122 | EventSystem eventSystem = EventSystem.current;
123 |
124 | if (eventSystem == null || eventSystem.currentSelectedGameObject == null) {
125 | return;
126 | }
127 |
128 | if (eventSystem.currentSelectedGameObject != selectedGameObject &&
129 | eventSystem.currentSelectedGameObject.transform.parent == scrollRect.content)
130 | {
131 | selectedGameObject = eventSystem.currentSelectedGameObject;
132 | selectedTransform = selectedGameObject.GetComponent();
133 | manualScrolling = false;
134 | }
135 | }
136 |
137 | private void SetScrollPosition()
138 | {
139 | if (selectedTransform == null || manualScrolling) {
140 | return;
141 | }
142 |
143 | switch (scrollDirection)
144 | {
145 | case ScrollDirection.Vertical:
146 | ScrollVertical(selectedTransform);
147 | break;
148 |
149 | case ScrollDirection.Horizontal:
150 | ScrollHorizontal(selectedTransform);
151 | break;
152 |
153 | case ScrollDirection.Both:
154 | ScrollVertical(selectedTransform);
155 | ScrollHorizontal(selectedTransform);
156 | break;
157 | }
158 | }
159 |
160 | private void ScrollVertical(RectTransform selection)
161 | {
162 | // Calculate the scroll offset
163 | float elementHeight = selection.rect.height;
164 | float maskHeight = scrollTransform.rect.height;
165 | float anchorPosition = scrollRect.content.anchoredPosition.y;
166 | float selectionPosition = -selection.anchoredPosition.y - (elementHeight * (1f - selection.pivot.y));
167 | float offset = GetScrollOffset(selectionPosition, anchorPosition, elementHeight, maskHeight);
168 |
169 | // Move the target scroll rect
170 | float position = scrollRect.verticalNormalizedPosition;
171 | position = Mathf.Clamp01(position + (offset / scrollRect.content.rect.height) * Time.unscaledDeltaTime * scrollSpeed);
172 | scrollRect.verticalNormalizedPosition = position;
173 | }
174 |
175 | private void ScrollHorizontal(RectTransform selection)
176 | {
177 | // Calculate the scroll offset
178 | float selectionPosition = -selection.anchoredPosition.x - (selection.rect.width * (1f - selection.pivot.x));
179 | float elementWidth = selection.rect.width;
180 | float maskWidth = scrollTransform.rect.width;
181 | float anchorPosition = -scrollRect.content.anchoredPosition.x;
182 | float offset = -GetScrollOffset(selectionPosition, anchorPosition, elementWidth, maskWidth);
183 |
184 | // Move the target scroll rect
185 | float position = scrollRect.horizontalNormalizedPosition;
186 | position = Mathf.Clamp01(position + (offset / scrollRect.content.rect.width) * Time.unscaledDeltaTime * scrollSpeed);
187 | scrollRect.horizontalNormalizedPosition = position;
188 | }
189 |
190 | private float GetScrollOffset(float position, float anchorPosition, float targetLength, float maskLength)
191 | {
192 | if (position < anchorPosition + (targetLength * 0.5f)) {
193 | return (anchorPosition + maskLength) - (position - targetLength);
194 | }
195 | else if (position + targetLength > anchorPosition + maskLength) {
196 | return (anchorPosition + maskLength) - (position + targetLength);
197 | }
198 |
199 | return 0f;
200 | }
201 |
202 | }
203 |
204 | }
205 |
--------------------------------------------------------------------------------
/Runtime/ScrollToSelection.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6ad76fd4d532d9e40b56ed26dcd17656
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/ScrollWithInput.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEngine.EventSystems;
3 | #if ENABLE_INPUT_SYSTEM
4 | using UnityEngine.InputSystem;
5 | #endif
6 | using UnityEngine.UI;
7 |
8 | namespace Zigurous.UI
9 | {
10 | ///
11 | /// Handles scrolling a ScrollRect component with user input. This is
12 | /// especially useful for controller support.
13 | ///
14 | [RequireComponent(typeof(ScrollRect))]
15 | [AddComponentMenu("Zigurous/UI/Navigation/Scroll With Input")]
16 | public class ScrollWithInput : MonoBehaviour
17 | {
18 | ///
19 | /// The ScrollRect component being scrolled (Read only).
20 | ///
21 | public ScrollRect scrollRect { get; private set; }
22 |
23 | #if ENABLE_INPUT_SYSTEM
24 | ///
25 | /// The input action that handles scrolling.
26 | ///
27 | [Tooltip("The input action that handles scrolling.")]
28 | public InputAction scrollInput = new InputAction("ScrollInput", InputActionType.Value, null, null, null, "Vector2");
29 | #endif
30 |
31 | #if ENABLE_LEGACY_INPUT_MANAGER
32 | ///
33 | /// The legacy input axis that handles scrolling in the y-axis.
34 | ///
35 | [Tooltip("The legacy input axis that handles scrolling in the y-axis.")]
36 | public string legacyScrollInputY = "";
37 |
38 | ///
39 | /// The legacy input axis that handles scrolling in the x-axis.
40 | ///
41 | [Tooltip("The legacy input axis that handles scrolling in the x-axis.")]
42 | public string legacyScrollInputX = "";
43 | #endif
44 |
45 | ///
46 | /// The sensitivity multiplier applied to the input.
47 | ///
48 | [Tooltip("The sensitivity multiplier applied to the input.")]
49 | public float sensitivity = 1f;
50 |
51 | ///
52 | /// The direction to scroll the ScrollRect.
53 | ///
54 | [Tooltip("The direction to scroll the ScrollRect.")]
55 | public ScrollDirection direction = ScrollDirection.Vertical;
56 |
57 | private void Awake()
58 | {
59 | scrollRect = GetComponent();
60 | }
61 |
62 | #if ENABLE_INPUT_SYSTEM
63 | private void Reset()
64 | {
65 | scrollInput = new InputAction("ScrollInput", InputActionType.Value, null, null, null, "Vector2");
66 | scrollInput.AddBinding("/rightStick");
67 | scrollInput.AddBinding("/leftStick");
68 | scrollInput.AddBinding("/dpad");
69 | }
70 |
71 | private void OnEnable()
72 | {
73 | scrollInput.Enable();
74 | }
75 |
76 | private void OnDisable()
77 | {
78 | scrollInput.Disable();
79 | }
80 | #endif
81 |
82 | private void Update()
83 | {
84 | EventSystem eventSystem = EventSystem.current;
85 |
86 | if (eventSystem == null || eventSystem.currentSelectedGameObject == null) {
87 | return;
88 | }
89 |
90 | if (eventSystem.currentSelectedGameObject == scrollRect.gameObject ||
91 | eventSystem.currentSelectedGameObject.transform.parent == scrollRect.content)
92 | {
93 | Vector2 input = Vector2.zero;
94 |
95 | #if ENABLE_INPUT_SYSTEM
96 | input = scrollInput.ReadValue();
97 | #endif
98 |
99 | #if ENABLE_LEGACY_INPUT_MANAGER
100 | if (input.y == 0f) {
101 | input.y = GetAxis(legacyScrollInputX);
102 | }
103 |
104 | if (input.x == 0f) {
105 | input.x = GetAxis(legacyScrollInputY);
106 | }
107 | #endif
108 |
109 | switch (direction)
110 | {
111 | case ScrollDirection.Vertical:
112 | input.x = 0f;
113 | break;
114 |
115 | case ScrollDirection.Horizontal:
116 | input.y = 0f;
117 | break;
118 | }
119 |
120 | scrollRect.normalizedPosition += input * sensitivity * Time.unscaledDeltaTime;
121 | }
122 | }
123 |
124 | #if ENABLE_LEGACY_INPUT_MANAGER
125 | private float GetAxis(string inputName)
126 | {
127 | float value = 0f;
128 |
129 | try
130 | {
131 | if (!string.IsNullOrEmpty(inputName)) {
132 | value = Input.GetAxis(inputName);
133 | }
134 | }
135 | catch
136 | {
137 | #if UNITY_EDITOR || DEVELOPMENT_BUILD
138 | Debug.LogWarning($"[ScrollWithInput] Input axis '{inputName}' is not setup.\nDefine the input in the Input Manager settings accessed from the menu: Edit > Project Settings");
139 | #endif
140 | }
141 |
142 | return value;
143 | }
144 | #endif
145 |
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/Runtime/ScrollWithInput.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b086e248ab0756c43ab350e4170c7a29
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/StretchToScreenSize.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace Zigurous.UI
4 | {
5 | ///
6 | /// Stretches a UI element to the screen size.
7 | ///
8 | [RequireComponent(typeof(RectTransform))]
9 | [AddComponentMenu("Zigurous/UI/Misc/Stretch to Screen Size")]
10 | public sealed class StretchToScreenSize : MonoBehaviour
11 | {
12 | ///
13 | /// The RectTransform component of the object.
14 | ///
15 | public RectTransform rectTransform { get; private set; }
16 |
17 | ///
18 | /// Stretches the width of the RectTransform to match the screen width.
19 | ///
20 | [Tooltip("Stretches the width of the RectTransform to match the screen width.")]
21 | public bool stretchWidth = true;
22 |
23 | ///
24 | /// Stretches the height of the RectTransform to match the screen height.
25 | ///
26 | [Tooltip("Stretches the height of the RectTransform to match the screen height.")]
27 | public bool stretchHeight = true;
28 |
29 | private void Awake()
30 | {
31 | rectTransform = GetComponent();
32 | }
33 |
34 | private void Start()
35 | {
36 | ScreenSizeListener.Instance.resized += OnScreenResize;
37 | }
38 |
39 | private void OnDestroy()
40 | {
41 | if (ScreenSizeListener.HasInstance) {
42 | ScreenSizeListener.Instance.resized -= OnScreenResize;
43 | }
44 | }
45 |
46 | private void OnEnable()
47 | {
48 | Stretch();
49 | }
50 |
51 | private void OnScreenResize(int width, int height)
52 | {
53 | if (enabled) {
54 | Stretch();
55 | }
56 | }
57 |
58 | ///
59 | /// Stretches the RectTransform to match the screen size.
60 | ///
61 | public void Stretch()
62 | {
63 | Stretch(stretchWidth, stretchHeight);
64 | }
65 |
66 | ///
67 | /// Stretches the RectTransform to match the screen size.
68 | ///
69 | /// Whether to stretch the width.
70 | /// Whether to stretch the height.
71 | public void Stretch(bool stretchWidth, bool stretchHeight)
72 | {
73 | if (stretchWidth)
74 | {
75 | rectTransform.SetAnchorMinX(0f);
76 | rectTransform.SetAnchorMaxX(1f);
77 | rectTransform.SetLeft(0f);
78 | rectTransform.SetRight(0f);
79 | }
80 |
81 | if (stretchHeight)
82 | {
83 | rectTransform.SetAnchorMinY(0f);
84 | rectTransform.SetAnchorMaxY(1f);
85 | rectTransform.SetBottom(0f);
86 | rectTransform.SetTop(0f);
87 | }
88 | }
89 |
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/Runtime/StretchToScreenSize.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6c834a245d125c94facf6505110f99ac
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/Zigurous.UI.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Zigurous.UI",
3 | "references": [
4 | "GUID:75469ad4d38634e559750d17036d5f7c"
5 | ],
6 | "includePlatforms": [],
7 | "excludePlatforms": [],
8 | "allowUnsafeCode": false,
9 | "overrideReferences": false,
10 | "precompiledReferences": [],
11 | "autoReferenced": true,
12 | "defineConstraints": [],
13 | "versionDefines": [],
14 | "noEngineReferences": false
15 | }
--------------------------------------------------------------------------------
/Runtime/Zigurous.UI.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d519592eaeb82894890523c42c9dbfe5
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Shaders.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 946c01f521bbf804dbeb46949b571f20
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Shaders/UIGradient.shader:
--------------------------------------------------------------------------------
1 | Shader "Zigurous/UI/Gradient"
2 | {
3 | Properties
4 | {
5 | [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
6 | [HideInInspector] _Color ("Tint", Color) = (1,1,1,1)
7 |
8 | [HideInInspector] _StencilComp ("Stencil Comparison", Float) = 8
9 | [HideInInspector] _Stencil ("Stencil ID", Float) = 0
10 | [HideInInspector] _StencilOp ("Stencil Operation", Float) = 0
11 | [HideInInspector] _StencilWriteMask ("Stencil Write Mask", Float) = 255
12 | [HideInInspector] _StencilReadMask ("Stencil Read Mask", Float) = 255
13 |
14 | [HideInInspector] _ColorMask ("Color Mask", Float) = 15
15 |
16 | _Rotation ("Rotation", Range(0, 180)) = 0
17 |
18 | [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
19 |
20 | [HideInInspector] _Color0 ("Color 0", Color) = (1, 1, 1, 1)
21 | [HideInInspector] _Color1 ("Color 1", Color) = (1, 1, 1, 1)
22 | [HideInInspector] _Color2 ("Color 2", Color) = (1, 1, 1, 1)
23 | [HideInInspector] _Color3 ("Color 3", Color) = (1, 1, 1, 1)
24 | [HideInInspector] _Color4 ("Color 4", Color) = (1, 1, 1, 1)
25 | [HideInInspector] _Color5 ("Color 5", Color) = (1, 1, 1, 1)
26 | [HideInInspector] _Color6 ("Color 6", Color) = (1, 1, 1, 1)
27 | [HideInInspector] _Color7 ("Color 7", Color) = (1, 1, 1, 1)
28 |
29 | [HideInInspector] _ColorTime0 ("Color Time 0", Float) = 0
30 | [HideInInspector] _ColorTime1 ("Color Time 1", Float) = 0
31 | [HideInInspector] _ColorTime2 ("Color Time 2", Float) = 0
32 | [HideInInspector] _ColorTime3 ("Color Time 3", Float) = 0
33 | [HideInInspector] _ColorTime4 ("Color Time 4", Float) = 0
34 | [HideInInspector] _ColorTime5 ("Color Time 5", Float) = 0
35 | [HideInInspector] _ColorTime6 ("Color Time 6", Float) = 0
36 | [HideInInspector] _ColorTime7 ("Color Time 7", Float) = 0
37 |
38 | [HideInInspector] _Colors ("Colors", Int) = 0
39 |
40 | [HideInInspector] _Alpha0 ("Alpha 0", Float) = 0
41 | [HideInInspector] _Alpha1 ("Alpha 1", Float) = 0
42 | [HideInInspector] _Alpha2 ("Alpha 2", Float) = 0
43 | [HideInInspector] _Alpha3 ("Alpha 3", Float) = 0
44 | [HideInInspector] _Alpha4 ("Alpha 4", Float) = 0
45 | [HideInInspector] _Alpha5 ("Alpha 5", Float) = 0
46 | [HideInInspector] _Alpha6 ("Alpha 6", Float) = 0
47 | [HideInInspector] _Alpha7 ("Alpha 7", Float) = 0
48 |
49 | [HideInInspector] _AlphaTime0 ("Alpha Time 0", Float) = 0
50 | [HideInInspector] _AlphaTime1 ("Alpha Time 1", Float) = 0
51 | [HideInInspector] _AlphaTime2 ("Alpha Time 2", Float) = 0
52 | [HideInInspector] _AlphaTime3 ("Alpha Time 3", Float) = 0
53 | [HideInInspector] _AlphaTime4 ("Alpha Time 4", Float) = 0
54 | [HideInInspector] _AlphaTime5 ("Alpha Time 5", Float) = 0
55 | [HideInInspector] _AlphaTime6 ("Alpha Time 6", Float) = 0
56 | [HideInInspector] _AlphaTime7 ("Alpha Time 7", Float) = 0
57 |
58 | [HideInInspector] _Alphas ("Alphas", Int) = 0
59 | }
60 |
61 | SubShader
62 | {
63 | Tags
64 | {
65 | "Queue"="Transparent"
66 | "IgnoreProjector"="True"
67 | "RenderType"="Transparent"
68 | "PreviewType"="Plane"
69 | "CanUseSpriteAtlas"="True"
70 | }
71 |
72 | Stencil
73 | {
74 | Ref [_Stencil]
75 | Comp [_StencilComp]
76 | Pass [_StencilOp]
77 | ReadMask [_StencilReadMask]
78 | WriteMask [_StencilWriteMask]
79 | }
80 |
81 | Cull Off
82 | Lighting Off
83 | ZWrite Off
84 | ZTest [unity_GUIZTestMode]
85 | Blend SrcAlpha OneMinusSrcAlpha
86 | ColorMask [_ColorMask]
87 |
88 | Pass
89 | {
90 | Name "Default"
91 |
92 | CGPROGRAM
93 |
94 | #pragma vertex vert
95 | #pragma fragment frag
96 | #pragma target 2.0
97 |
98 | #include "UnityCG.cginc"
99 | #include "UnityUI.cginc"
100 |
101 | #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
102 | #pragma multi_compile_local _ UNITY_UI_ALPHACLIP
103 |
104 | struct appdata_t
105 | {
106 | float4 vertex : POSITION;
107 | float4 color : COLOR;
108 | float2 texcoord : TEXCOORD0;
109 |
110 | UNITY_VERTEX_INPUT_INSTANCE_ID
111 | };
112 |
113 | struct v2f
114 | {
115 | float4 vertex : SV_POSITION;
116 | fixed4 color : COLOR;
117 | float2 texcoord : TEXCOORD0;
118 | float4 worldPosition : TEXCOORD1;
119 |
120 | UNITY_VERTEX_OUTPUT_STEREO
121 | };
122 |
123 | sampler2D _MainTex;
124 | fixed4 _Color;
125 | fixed4 _TextureSampleAdd;
126 | float4 _ClipRect;
127 | float4 _MainTex_ST;
128 | float _Rotation;
129 |
130 | float4 _Color0, _Color1, _Color2, _Color3, _Color4, _Color5, _Color6, _Color7;
131 | float _Alpha0, _Alpha1, _Alpha2, _Alpha3, _Alpha4, _Alpha5, _Alpha6, _Alpha7;
132 | float _ColorTime0, _ColorTime1, _ColorTime2, _ColorTime3, _ColorTime4, _ColorTime5, _ColorTime6, _ColorTime7;
133 | float _AlphaTime0, _AlphaTime1, _AlphaTime2, _AlphaTime3, _AlphaTime4, _AlphaTime5, _AlphaTime6, _AlphaTime7;
134 | int _Colors, _Alphas;
135 |
136 | float4 get_gradient (float2 texcoord)
137 | {
138 | float4 cc[8] = { _Color0, _Color1, _Color2, _Color3, _Color4, _Color5, _Color6, _Color7 };
139 | float aa[8] = { _Alpha0, _Alpha1, _Alpha2, _Alpha3, _Alpha4, _Alpha5, _Alpha6, _Alpha7 };
140 | float ct[8] = { _ColorTime0, _ColorTime1, _ColorTime2, _ColorTime3, _ColorTime4, _ColorTime5, _ColorTime6, _ColorTime7 };
141 | float at[8] = { _AlphaTime0, _AlphaTime1, _AlphaTime2, _AlphaTime3, _AlphaTime4, _AlphaTime5, _AlphaTime6, _AlphaTime7 };
142 |
143 | float4 cv1 = cc[0], cv2 = cc[_Colors - 1];
144 | float ct1 = ct[0], ct2 = ct[_Colors - 1];
145 | float av1 = aa[0], av2 = aa[_Alphas - 1];
146 | float at1 = at[0], at2 = at[_Alphas - 1];
147 |
148 | float t = texcoord.x;
149 |
150 | for (int i = 0; i < _Colors; i++)
151 | {
152 | if (ct[i] > t)
153 | break;
154 |
155 | cv1 = cc[i];
156 | ct1 = ct[i];
157 | }
158 |
159 | for (int j = 0; j < _Colors; j++)
160 | {
161 | if (ct[j] < t)
162 | continue;
163 |
164 | cv2 = cc[j];
165 | ct2 = ct[j];
166 | break;
167 | }
168 |
169 | for (int k = 0; k < _Alphas; k++)
170 | {
171 | if (at[k] > t)
172 | break;
173 |
174 | av1 = aa[k];
175 | at1 = at[k];
176 | }
177 |
178 | for (int l = 0; l < _Alphas; l++)
179 | {
180 | if (at[l] < t)
181 | continue;
182 |
183 | av2 = aa[l];
184 | at2 = at[l];
185 | break;
186 | }
187 |
188 | float lerpA = (t - at1) / (at2 - at1);
189 | float lerpC = (t - ct1) / (ct2 - ct1);
190 | float4 finalC = lerp(cv1, cv2, lerpC);
191 | float4 finalA = lerp(av1, av2, lerpA);
192 | finalC.a = finalA;
193 |
194 | return finalC;
195 | }
196 |
197 | v2f vert (appdata_t v)
198 | {
199 | v2f OUT;
200 | UNITY_SETUP_INSTANCE_ID(v);
201 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
202 | OUT.worldPosition = v.vertex;
203 | OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
204 |
205 | OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
206 | OUT.color = v.color * _Color;
207 |
208 | const float Deg2Rad = (UNITY_PI * 2.0) / 360.0;
209 | float rotationRadians = _Rotation * Deg2Rad;
210 | float s = sin(rotationRadians);
211 | float c = cos(rotationRadians);
212 | float2x2 rotationMatrix = float2x2(c, -s, s, c);
213 | OUT.texcoord.xy = mul(v.texcoord.xy, rotationMatrix);
214 |
215 | return OUT;
216 | }
217 |
218 | fixed4 frag (v2f IN) : SV_Target
219 | {
220 | half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
221 |
222 | #ifdef UNITY_UI_CLIP_RECT
223 | color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
224 | #endif
225 |
226 | #ifdef UNITY_UI_ALPHACLIP
227 | clip (color.a - 0.001);
228 | #endif
229 |
230 | float2 texcoord = (IN.texcoord - _MainTex_ST.zw) / _MainTex_ST.xy;
231 | float4 gradient = get_gradient(texcoord);
232 | return color * gradient;
233 | }
234 |
235 | ENDCG
236 |
237 | }
238 |
239 | }
240 |
241 | CustomEditor "Zigurous.UI.Editor.UIGradientShaderGUI"
242 | }
243 |
--------------------------------------------------------------------------------
/Shaders/UIGradient.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2dd4e86295075a24c94a2a99d4dceb5e
3 | ShaderImporter:
4 | externalObjects: {}
5 | defaultTextures: []
6 | nonModifiableTextures: []
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.zigurous.ui",
3 | "version": "0.3.0",
4 | "displayName": "UI Toolkit",
5 | "description": "The UI Toolkit package contains scripts and utilities for creating UI in Unity projects. The package is intended to solve common problems that arise when developing UI and menus.",
6 | "unity": "2019.4",
7 | "repository": "https://github.com/zigurous/unity-ui-toolkit",
8 | "documentationUrl": "https://docs.zigurous.com/com.zigurous.ui",
9 | "changelogUrl": "https://docs.zigurous.com/com.zigurous.ui/changelog",
10 | "licensesUrl": "https://docs.zigurous.com/com.zigurous.ui/license",
11 | "keywords": [
12 | "ui",
13 | "menus",
14 | "navigation",
15 | "scrolling",
16 | "masking",
17 | "letterboxing"
18 | ],
19 | "publishConfig": {
20 | "registry": "https://npm.pkg.github.com/@zigurous"
21 | },
22 | "author": {
23 | "name": "Zigurous",
24 | "email": "support@zigurous.com",
25 | "url": "https://zigurous.com"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 12b5a06af5493f14cb503e73f1a3d167
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------