Merge pull request #413 from Unity-UI-Extensions/feature/V2.3.0

Feature/v2.3.0
pull/429/head
Simon (Darkside) Jackson 2023-02-07 14:06:08 +00:00 committed by GitHub
commit 8cbd1c3c1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
113 changed files with 4682 additions and 1797 deletions

1
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1 @@
* SimonDarksideJ

6
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,6 @@
# These are supported funding model platforms
github: [SimonDarksideJ]
ko_fi: Ko-fi.com/uiextensions
issuehunt: simondarksidej
custom: https://paypal.me/unityuiextensions

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,44 @@
---
name: Bug report
about: Create a report to identify a potential issue
title: 'BUG: '
labels: bug
assignees: ''
---
# Unity UI Extensions Bug Report
## Describe the bug
<!-- Please provide a clear and concise description of what the bug is. -->
## To Reproduce
<!-- Include Steps to reproduce the behavior: -->
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
## Actual behavior
<!-- What is actually happening -->
## Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
## Your Setup
<!-- please complete any/all the following information. -->
- **Operation System:**
- [ ] Windows
- [ ] MacOs
- [ ] Linux
- [ ] Other <!-- Please Specify Platform -->
- **Unity Version:** <!-- Please Specify Version --> 2020.3.15f
- **Unity UI Extensions Version**
- [ ] 2.3.0 <!-- Please Specify Version or commit sha -->
## Additional context
<!-- Add any other context about the problem here. -->

View File

@ -0,0 +1,30 @@
---
name: Feature request
about: Suggest an idea for the Unity UI Extensions
title: 'Feature Request: '
labels: enhancement
assignees: ''
---
# Unity UI Extensions Feature Request
## Is your feature request related to a problem? Please describe
<!--Please provide a clear and concise description of what the problem is.
E.g. I'm always frustrated when [...]-->
## How would you classify your suggestion
<!--What type of enhancement is it, e.g:-->
- New platform support
- Usability / Configuration
- Architecture / Services
## Describe the solution you'd like
<!--A clear and concise description of what you want to happen.-->
## Describe alternatives you've considered
<!--A clear and concise description of any alternative solutions or features you've considered.-->
## Additional context
<!--Add any other context or screenshots about the feature request here.-->

View File

@ -0,0 +1,30 @@
---
name: Request for Information
about: Not sure how to do something, just ask.
title: 'RFI: '
labels: question
assignees: ''
---
# Unity UI Extensions Request for Information
<!-- As imperfect beings, we try to teach and show how to make using the framework easy to handle, but sometimes we will fall short. Help us to better educate adopters by pointing out where we need to give more information. -->
## What are you trying to achieve?
<!--
Add a clear and concise description of what is it you are trying to implement.
Include screenshots or examples from other projects if it helps.
-->
## What have you already tried
<!--
Have you tried to complete the task yourself but couldn't figure it out, if so what and why?
-->
## What material have you referenced that didn't answer your question
<!--
What other content have you tried reading / viewing that didn't answer your question?
-->

30
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,30 @@
# Unity UI Extensions - Pull Request
## Overview
<!-- Please provide a clear and concise description of the pull request. -->
## Changes
<!-- Brief list of the targeted features that are being changed. -->
- Fixes: <!--issue number or url-->
## Breaking Changes
<!-- Are there any breaking changes included in this change that would prevent or cause issue for existing projects? -->
- Breaks
## Related Submodule Changes
<!-- Include any submodule related Pull Request links here -->
- URL
## Testing status
<!-- Remove the options that do not apply -->
* No tests have been added.
* Includes unit tests.
* Includes performance tests.
* Includes integration tests.
### Manual testing status
<!-- Describe how you tested your implementation/fix. Try to mention all the cases and flows. -->
<!-- It will help the reviewer to understand if you missed any cases or test steps as well as will tell more about your feature or fix. -->

37
.github/workflows/buildupmpackages.yml vendored Normal file
View File

@ -0,0 +1,37 @@
name: Build and test UPM packages for platforms on all available Unity Versions
on:
pull_request:
branches-ignore:
- 'release'
# Ignore PRs targetting main
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
# Run Unity build unit tests defined in the package for a single version for feature branches
Run-Partial-Unit-Tests:
name: Run Unity Unit Tests
if: github.ref != 'refs/heads/development'
uses: ./.github/workflows/rununitysinglebuild.yml
with:
unityversion: 2020.3
# Run Unity multi-version build unit tests defined in the package for the development branch
Run-Full-Unit-Tests:
name: Run Unity Unit Tests
if: github.ref == 'refs/heads/development'
uses: ./.github/workflows/rununitybuildmultiversion.yml
# Update the package release version
Update-Version:
name: Update Package Version
uses: ./.github/workflows/tagrelease.yml
with:
build-target: windows
secrets: inherit

View File

@ -0,0 +1,459 @@
name: Run Unity Builds
on:
workflow_call:
inputs:
dependencies:
description: "json array of dependencies and their targets"
required: false
type: string
jobs:
run_build:
name: Run Unity Build process
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: windows
unityVersion: 2019.4
build-target: Android
- os: macos
unityVersion: 2019.4
build-target: iOS
- os: windows
unityVersion: 2019.4
build-target: StandaloneWindows64
- os: windows
unityVersion: 2019.4
build-target: WSAPlayer
- os: windows
unityVersion: 2020.3
build-target: Android
- os: macos
unityVersion: 2020.3
build-target: iOS
- os: windows
unityVersion: 2020.3
build-target: StandaloneWindows64
- os: windows
unityVersion: 2020.3
build-target: WSAPlayer
- os: windows
unityVersion: 2021.3
build-target: Android
- os: macos
unityVersion: 2021.3
build-target: iOS
- os: windows
unityVersion: 2021.3
build-target: StandaloneWindows64
- os: windows
unityVersion: 2021.3
build-target: WSAPlayer
- os: windows
unityVersion: 2022.2
build-target: Android
- os: macos
unityVersion: 2022.2
build-target: iOS
- os: windows
unityVersion: 2022.2
build-target: StandaloneWindows64
- os: windows
unityVersion: 2022.2
build-target: WSAPlayer
steps:
- name: Script Version
run: |
echo "::group::Script Versioning"
$scriptVersion = "1.0.0"
echo "Build Script Version: $scriptVersion"
echo "::endgroup::"
shell: pwsh
- uses: actions/checkout@v3
with:
submodules: recursive
clean: true
- id: build
name: 'Run Unity Builds'
run: |
echo "::group::Set Hub and editor locations"
$unityVersion = ${{ matrix.unityVersion }}
echo "::group::Set Hub and editor locations"
## Set Hub and editor locations
if ( (-not $global:PSVersionTable.Platform) -or ($global:PSVersionTable.Platform -eq "Win32NT") )
{
$hubPath = "C:\Program Files\Unity Hub\Unity Hub.exe"
$editorRootPath = "C:\Program Files\Unity\Hub\Editor\"
$editorFileEx = "\Editor\Unity.exe"
#"Unity Hub.exe" -- --headless help
#. 'C:\Program Files\Unity Hub\Unity Hub.exe' -- --headless help
function unity-hub
{
& $hubPath -- --headless $args.Split(" ") | Out-String -NoNewline
}
}
elseif ( $global:PSVersionTable.OS.Contains("Darwin") )
{
$hubPath = "/Applications/Unity Hub.app/Contents/MacOS/Unity Hub"
$editorRootPath = "/Applications/Unity/Hub/Editor/"
$editorFileEx = "/Unity.app/Contents/MacOS/Unity"
# /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless help
function unity-hub
{
& $hubPath -- --headless $args.Split(" ") | Out-String -NoNewline
}
}
elseif ( $global:PSVersionTable.OS.Contains("Linux") )
{
$hubPath = "$HOME/Unity Hub/UnityHub.AppImage"
$editorRootPath = "$HOME/Unity/Hub/Editor/"
$editorFileEx = "/Editor/Unity"
# /UnityHub.AppImage --headless help
# xvfb-run --auto-servernum "$HOME/Unity Hub/UnityHub.AppImage" --headless help
function unity-hub
{
xvfb-run --auto-servernum "$hubPath" --headless $args.Split(" ")
}
}
echo "::endgroup::"
echo "::group::Get String function to query a string for a value"
function GetString($InputString, $InputPattern, $MatchIndex)
{
$regExResult = $InputString | Select-String -Pattern $InputPattern
if($regExResult.Length -gt 0)
{
return $regExResult.Matches[$MatchIndex].Value
}
else
{
return 0
}
}
function Get-LetterCount
{
Param ([string]$string)
return $string.Length
}
echo "::endgroup::"
echo "::group::Get Installed Unity version based on Matrix"
echo 'Script Start'
echo "Unity hub path is {$hubPath}"
echo "Requested unity version is {$unityVersion}"
$InstalledUnityVersions = unity-hub editors
$editorRootPath = unity-hub ip -g
echo "Installed unity versions are {$InstalledUnityVersions}"
echo "Unity install path is {$editorRootPath}"
$versionLength = Get-LetterCount $unityVersion
if ($versionLength -eq 4) {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion.{4,7}" -MatchIndex 0
}
elseif ($versionLength -eq 6) {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion.{4,5}" -MatchIndex 0
}
else {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion" -MatchIndex 0
}
echo "Found unity version is {$queryUnityVersion}"
if ($queryUnityVersion -ne 0)
{
$unityVersion = $queryUnityVersion.Trim(","," ").Trim()
echo "Long Unity version is $unityVersion"
}
else
{
echo "Unity $unityVersion not found on this machine, skipping"
exit 0
}
echo "::endgroup::"
echo "::group::Search for Editor if not found"
$checkPath = Join-Path $editorRootPath $unityVersion
echo "Testing for editor at $checkPath"
while (-not (Test-Path "$checkPath")) {
$source = $unityVersion.Replace("f1","")
$newversion = $source.Split(".")
$newversion[2] = [int]$newversion[2] - 1
if ([int]$newversion[2] -lt 1) {
echo "Unity ${{ matrix.unityVersion }} not found on this machine, skipping"
exit 0
}
$newunityVersion = "{0}.{1}.{2}f1" -f $newversion[0],$newversion[1],$newversion[2]
echo "Unity $unityVersion not found on this machine, trying $newunityVersion"
$unityVersion = $newunityVersion
$checkPath = Join-Path $editorRootPath $unityVersion
}
echo "::endgroup::"
echo "::group::Set editor locations"
if ( (-not $global:PSVersionTable.Platform) -or ($global:PSVersionTable.Platform -eq "Win32NT") ) {
echo 'Building using Windows'
$editorFileEx = "/Editor/Unity.exe"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
#$p = Start-Process -Verbose -NoNewWindow -PassThru -Wait -FilePath "$editorrunpath" -ArgumentList (@(' -batchmode') + $args.Split(" "))
& $editorrunpath -batchmode $args.Split(" ") | Out-String
}
}
elseif ( $global:PSVersionTable.OS.Contains("Darwin") ) {
echo 'Building using Mac'
$editorFileEx = "/Unity.app/Contents/MacOS/Unity"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
#$p = Start-Process -Verbose -NoNewWindow -PassThru -Wait -FilePath "$editorrunpath" -ArgumentList (@(' -batchmode') + $args.Split(" "))
& $editorrunpath -batchmode $args.Split(" ") | Out-String
}
}
elseif ( $global:PSVersionTable.OS.Contains("Linux") ) {
echo 'Building using Linux'
$editorFileEx = "/Editor/Unity"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
xvfb-run --auto-servernum "$editorrunpath" -batchmode $args.Split(" ")
}
}
else
{
echo 'Unknown build platform'
}
echo "::endgroup::"
echo "::group::Test Unity version is installed"
if ( -not (Test-Path "$editorrunpath") )
{
Write-Error "Editor not Found for $unityVersion"
exit 1
}
else {
echo "Editor Path is {$editorrunpath}"
}
echo "::endgroup::"
echo "::group::Setup logging and run Unit tests"
# Log detail
$logDirectory = "Logs"
if (Test-Path -Path $logDirectory) {
echo "Clearing logs from a previous run"
Remove-item $logDirectory -recurse
}
$logDirectory = New-Item -ItemType Directory -Force -Path $logDirectory | Select-Object
echo "Log Directory: $logDirectory"
$date = Get-Date -Format "yyyyMMddTHHmmss"
# If run manually, the Refname is actually blank, so just use date
if([string]::IsNullOrEmpty(${GITHUB_REF_NAME})) {
$logName = "$logDirectory$directorySeparatorChar$date"
}
else{
$logName = "$logDirectory$directorySeparatorChar${GITHUB_REF_NAME}-$date"
}
$logPath = "$logName.log"
$testsLogPath = "$logName-tests.xml"
echo "Logpath [$logPath]"
echo "TestsPath [$testsLogPath]"
echo "::endgroup::"
echo "::group::Grouping Package in a UPM folder"
$UPMFolderName = 'u'
if ( -not (Test-Path '$UPMFolderName') )
{
New-Item $UPMFolderName -ItemType Directory
}
Move-Item -Path * -Destination $UPMFolderName -exclude $UPMFolderName
echo "::endgroup::"
echo "::group::Creating Temp Unity project"
$TempUnityProjectName = 'P'
unity-editor '-createProject' $TempUnityProjectName -quit
$destinationPath = $TempUnityProjectName + $directorySeparatorChar + 'packages'
Move-Item -Path $UPMFolderName -Destination $destinationPath
echo "::endgroup::"
echo "::group::If required, clone dependencies in to test project"
<# Dependency option requires specific inputs
* A dependency input string in json format, listing each dependency by name and git url, e.g.
$dependencies = '[{"ASADependencies": "github.com/SimonDarksideJ/upmGithubActionsTests.git"}]'
*Note, remove the https:// portion to allow using a PAT to access the repo
The Name of the dependency should ALSO MATCH the name of the branch on the repo where the dependency is held (files intended for the packages folder)
* Additionally, if Manifest entries are required, then a manifest file with those dependencies (and ONLY the new dependancies) should also be in the dependency branch named the same as the branch name
e.g. "ASADependencies.json" - keep the same structure, but only the dependancy entries
!!Does NOT support additional scoped registries at this time! #>
echo "---------------------------------------------"
echo "Read dependancy input value"
if([string]::IsNullOrEmpty('${{ inputs.dependencies }}'))
{
echo "No dependencies provided"
echo "input ${{ inputs.dependencies }}"
echo "------------------------------"
}
else {
echo "dependencies provided, validating"
# Read dependancy input value
$dependencies = '${{ inputs.dependencies }}'
if([string]::IsNullOrEmpty('${{ secrets.GIT_USER_NAME }}') -or [string]::IsNullOrEmpty('${{ secrets.GIT_PAT }}')){
echo ""
echo "Secrets for GIT_USER_NAME or GIT_PAT missing, please register them with access to this runner"
echo "*Note, Organisation secrets are not accessible to Forked repos and need registering in the local fork"
exit 1
}
echo "---------------------------------------------"
echo "Read dependancy input values as json"
$JSONdependencies = $dependencies | ConvertFrom-Json
echo $JSONdependencies
# Read current Manifest json
$manifestPath = $destinationPath + $directorySeparatorChar + 'manifest.json'
$projectManifest = Get-Content -Path $manifestPath | ConvertFrom-Json
$strArray = $projectManifest.dependencies.PsObject.Properties | ForEach-Object {"$($_.Name)@$($_.Value),"}
echo "---------------------------------------------"
echo "Loop through new dependancies and add them to the project Manifest"
foreach($dependency in $JSONdependencies){
$dependency.PsObject.Properties | ForEach-Object -Process {
$dependencyName = $_.Name
$dependencyPath = $dependencyName.Replace("/","_")
$dependencyURL = $_.Value
echo "---------------------------------------------"
echo "Cloning dependency - Name [$dependencyName] - Path [$dependencyPath] - URL [$dependencyURL]"
$cloneURL = "https://${{ secrets.GIT_USER_NAME }}:${{ secrets.GIT_PAT }}@$dependencyURL"
echo "cloning $dependencyName from $dependencyURL and moving to $destinationPath"
echo "git path - $cloneURL"
# Clone Dependancy repo to destination folder
git clone -b $dependencyName --single-branch $cloneURL $dependencyPath
if( -not (Test-Path -Path "$dependencyPath")){
echo "Unable to clone $dependencyName from $dependencyURL"
exit 1
}
# Move files from clone path into packages folder, if the dependency contains a UPM package then move the entire folder and not just its contents
if (Test-Path -Path "$dependencyPath/package.json") {
$package_json = Get-Content -Path $dependencyPath/package.json | ConvertFrom-Json
$packageName = $package_json.name
Rename-Item $dependencyPath $packageName
echo "Moving whole $packageName UPM package to $destinationPath"
Move-Item -Path "$packageName" -Destination $destinationPath
}
else {
echo "Moving the contents of $dependencyName into the $destinationPath folder"
Move-Item -Path "$dependencyPath/*" -Destination $destinationPath
}
# Get Dependency manifest entries (if applicable)
if (Test-Path -Path "$destinationPath/$dependencyName.json") {
$dependencyManifest = Get-Content -Path "$destinationPath/$dependencyName.json" | ConvertFrom-Json
$dependencyManifest.dependencies.PsObject.Properties | ForEach-Object {
$strArray += "$($_.Name)@$($_.Value),"
}
}
else{
echo "No denendency json found called $destinationPath/$dependencyName.json, skipping adding additional manifest entries"
}
}
}
echo "---------------------------------------------"
# Reformat combined dependancies list
$strArray = $strArray.Trim(",") | ConvertTo-Json
$strArray = $strArray.Replace("@",'":"').Replace("[","{").Replace("]","}")
$strArrayObject = $strArray | ConvertFrom-Json
# Save manifest back to project
$projectManifest.dependencies = $strArrayObject
$projectManifest | ConvertTo-Json | Set-Content -Path "$destinationPath/manifest.json"
echo "Project updated with the following dependencies"
echo "-----------------------------------------------"
echo $projectManifest
}
echo "::endgroup::"
echo "::group::Run build"
echo "---------------------------------------------"
echo "Start Testing"
echo "Unity Command\n[unity-editor -projectPath $TempUnityProjectName -logfile $logPath -batchmode -nographics -quit -buildTarget ${{ matrix.build-target }}]"
unity-editor -projectPath $TempUnityProjectName -logfile $logPath -batchmode -nographics -quit -buildTarget ${{ matrix.build-target }}
echo "---------------------------------------------"
echo "::group::Unity Unit tests Results"
if (Test-Path $testsLogPath) {
echo "Test Run results for ${GITHUB_REPOSITORY} Branch ${GITHUB_REF}"
echo ""
Select-Xml -Path $testsLogPath -XPath '/test-run/test-suite' | ForEach-Object { "Name: " +$_.Node.name, ", Result: " + $_.Node.result, ", Total Tests: " + $_.Node.total, ", Passed: " + $_.Node.passed, ", Failed: " + $_.Node.failed, ", Skipped: " + $_.Node.skipped }
}
else {
echo "No test results found for ${GITHUB_REPOSITORY} Branch ${GITHUB_REF} at $testsLogPath"
echo ""
}
echo "::endgroup::"
if($LASTEXITCODE -ne '0'){
echo "::group::Unity Unit tests errors"
$exitCode = $testResult.ExitCode
Get-Content $logPath
echo "Build failed due to errors ($LASTEXITCODE), please check the log at $logPath"
echo "::endgroup::"
exit $LASTEXITCODE
}
echo "::endgroup::"
shell: pwsh
- uses: actions/upload-artifact@v3
if: always()
with:
name: unity-build-log
path: Logs/**

View File

@ -0,0 +1,424 @@
name: Run Limited Unity Builds
on:
workflow_call:
inputs:
unityVersion:
description: "The version of Unity to validate on"
required: true
type: string
dependencies:
description: "json array of dependencies and their targets"
required: false
type: string
jobs:
run_build:
name: Run Unity Build process
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: macos
build-target: iOS
- os: windows
build-target: Android
- os: windows
build-target: StandaloneWindows64
- os: windows
build-target: WSAPlayer
steps:
- name: Script Version
run: |
echo "::group::Script Versioning"
$scriptVersion = "1.0.0"
echo "Build Script Version: $scriptVersion"
echo "::endgroup::"
shell: pwsh
- uses: actions/checkout@v3
with:
submodules: recursive
clean: true
- id: build
name: 'Run Unity Builds'
run: |
echo "::group::Set Hub and editor locations"
$unityVersion = ${{ inputs.unityVersion }}
echo "::group::Set Hub and editor locations"
## Set Hub and editor locations
if ( (-not $global:PSVersionTable.Platform) -or ($global:PSVersionTable.Platform -eq "Win32NT") )
{
$hubPath = "C:\Program Files\Unity Hub\Unity Hub.exe"
$editorRootPath = "C:\Program Files\Unity\Hub\Editor\"
$editorFileEx = "\Editor\Unity.exe"
#"Unity Hub.exe" -- --headless help
#. 'C:\Program Files\Unity Hub\Unity Hub.exe' -- --headless help
function unity-hub
{
& $hubPath -- --headless $args.Split(" ") | Out-String -NoNewline
}
}
elseif ( $global:PSVersionTable.OS.Contains("Darwin") )
{
$hubPath = "/Applications/Unity Hub.app/Contents/MacOS/Unity Hub"
$editorRootPath = "/Applications/Unity/Hub/Editor/"
$editorFileEx = "/Unity.app/Contents/MacOS/Unity"
# /Applications/Unity\ Hub.app/Contents/MacOS/Unity\ Hub -- --headless help
function unity-hub
{
& $hubPath -- --headless $args.Split(" ") | Out-String -NoNewline
}
}
elseif ( $global:PSVersionTable.OS.Contains("Linux") )
{
$hubPath = "$HOME/Unity Hub/UnityHub.AppImage"
$editorRootPath = "$HOME/Unity/Hub/Editor/"
$editorFileEx = "/Editor/Unity"
# /UnityHub.AppImage --headless help
# xvfb-run --auto-servernum "$HOME/Unity Hub/UnityHub.AppImage" --headless help
function unity-hub
{
xvfb-run --auto-servernum "$hubPath" --headless $args.Split(" ")
}
}
echo "::endgroup::"
echo "::group::Get String function to query a string for a value"
function GetString($InputString, $InputPattern, $MatchIndex)
{
$regExResult = $InputString | Select-String -Pattern $InputPattern
if($regExResult.Length -gt 0)
{
return $regExResult.Matches[$MatchIndex].Value
}
else
{
return 0
}
}
function Get-LetterCount
{
Param ([string]$string)
return $string.Length
}
echo "::endgroup::"
echo "::group::Get Installed Unity version based on Matrix"
echo 'Script Start'
echo "Unity hub path is {$hubPath}"
echo "Requested unity version is {$unityVersion}"
$InstalledUnityVersions = unity-hub editors
$editorRootPath = unity-hub ip -g
echo "Installed unity versions are {$InstalledUnityVersions}"
echo "Unity install path is {$editorRootPath}"
$versionLength = Get-LetterCount $unityVersion
if ($versionLength -eq 4) {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion.{4,7}" -MatchIndex 0
}
elseif ($versionLength -eq 6) {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion.{4,5}" -MatchIndex 0
}
else {
$queryUnityVersion = GetString $InstalledUnityVersions "$unityVersion" -MatchIndex 0
}
echo "Found unity version is {$queryUnityVersion}"
if ($queryUnityVersion -ne 0)
{
$unityVersion = $queryUnityVersion.Trim(","," ").Trim()
echo "Long Unity version is $unityVersion"
}
else
{
echo "Unity $unityVersion not found on this machine, skipping"
exit 0
}
echo "::endgroup::"
echo "::group::Search for Editor if not found"
$checkPath = Join-Path $editorRootPath $unityVersion
echo "Testing for editor at $checkPath"
while (-not (Test-Path "$checkPath")) {
$source = $unityVersion.Replace("f1","")
$newversion = $source.Split(".")
$newversion[2] = [int]$newversion[2] - 1
if ([int]$newversion[2] -lt 1) {
echo "Unity ${{ inputs.unityVersion }} not found on this machine, skipping"
exit 0
}
$newunityVersion = "{0}.{1}.{2}f1" -f $newversion[0],$newversion[1],$newversion[2]
echo "Unity $unityVersion not found on this machine, trying $newunityVersion"
$unityVersion = $newunityVersion
$checkPath = Join-Path $editorRootPath $unityVersion
}
echo "::endgroup::"
echo "::group::Set editor locations"
if ( (-not $global:PSVersionTable.Platform) -or ($global:PSVersionTable.Platform -eq "Win32NT") ) {
echo 'Building using Windows'
$editorFileEx = "/Editor/Unity.exe"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
#$p = Start-Process -Verbose -NoNewWindow -PassThru -Wait -FilePath "$editorrunpath" -ArgumentList (@(' -batchmode') + $args.Split(" "))
& $editorrunpath -batchmode $args.Split(" ") | Out-String
}
}
elseif ( $global:PSVersionTable.OS.Contains("Darwin") ) {
echo 'Building using Mac'
$editorFileEx = "/Unity.app/Contents/MacOS/Unity"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
#$p = Start-Process -Verbose -NoNewWindow -PassThru -Wait -FilePath "$editorrunpath" -ArgumentList (@(' -batchmode') + $args.Split(" "))
& $editorrunpath -batchmode $args.Split(" ") | Out-String
}
}
elseif ( $global:PSVersionTable.OS.Contains("Linux") ) {
echo 'Building using Linux'
$editorFileEx = "/Editor/Unity"
$editorrunpath = Join-Path $editorRootPath $unityVersion $editorFileEx
function unity-editor {
xvfb-run --auto-servernum "$editorrunpath" -batchmode $args.Split(" ")
}
}
else
{
echo 'Unknown build platform'
}
echo "::endgroup::"
echo "::group::Test Unity version is installed"
if ( -not (Test-Path "$editorrunpath") )
{
Write-Error "Editor not Found for $unityVersion"
exit 1
}
else {
echo "Editor Path is {$editorrunpath}"
}
echo "::endgroup::"
echo "::group::Setup logging and run Unit tests"
# Log detail
$logDirectory = "Logs"
if (Test-Path -Path $logDirectory) {
echo "Clearing logs from a previous run"
Remove-item $logDirectory -recurse
}
$logDirectory = New-Item -ItemType Directory -Force -Path $logDirectory | Select-Object
echo "Log Directory: $logDirectory"
$date = Get-Date -Format "yyyyMMddTHHmmss"
# If run manually, the Refname is actually blank, so just use date
if([string]::IsNullOrEmpty(${GITHUB_REF_NAME})) {
$logName = "$logDirectory$directorySeparatorChar$date"
}
else{
$logName = "$logDirectory$directorySeparatorChar${GITHUB_REF_NAME}-$date"
}
$logPath = "$logName.log"
$testsLogPath = "$logName-tests.xml"
echo "Logpath [$logPath]"
echo "TestsPath [$testsLogPath]"
echo "::endgroup::"
echo "::group::Grouping Package in a UPM folder"
$UPMFolderName = 'u'
if ( -not (Test-Path '$UPMFolderName') )
{
New-Item $UPMFolderName -ItemType Directory
}
Move-Item -Path * -Destination $UPMFolderName -exclude $UPMFolderName
echo "::endgroup::"
echo "::group::Creating Temp Unity project"
$TempUnityProjectName = 'P'
unity-editor '-createProject' $TempUnityProjectName -quit
$destinationPath = $TempUnityProjectName + $directorySeparatorChar + 'packages'
Move-Item -Path $UPMFolderName -Destination $destinationPath
echo "::endgroup::"
echo "::group::If required, clone dependencies in to test project"
<# Dependency option requires specific inputs
* A dependency input string in json format, listing each dependency by name and git url, e.g.
$dependencies = '[{"ASADependencies": "github.com/SimonDarksideJ/upmGithubActionsTests.git"}]'
*Note, remove the https:// portion to allow using a PAT to access the repo
The Name of the dependency should ALSO MATCH the name of the branch on the repo where the dependency is held (files intended for the packages folder)
* Additionally, if Manifest entries are required, then a manifest file with those dependencies (and ONLY the new dependancies) should also be in the dependency branch named the same as the branch name
e.g. "ASADependencies.json" - keep the same structure, but only the dependancy entries
!!Does NOT support additional scoped registries at this time! #>
echo "---------------------------------------------"
echo "Read dependancy input value"
if([string]::IsNullOrEmpty('${{ inputs.dependencies }}'))
{
echo "No dependencies provided"
echo "input ${{ inputs.dependencies }}"
echo "------------------------------"
}
else {
echo "dependencies provided, validating"
# Read dependancy input value
$dependencies = '${{ inputs.dependencies }}'
if([string]::IsNullOrEmpty('${{ secrets.GIT_USER_NAME }}') -or [string]::IsNullOrEmpty('${{ secrets.GIT_PAT }}')){
echo ""
echo "Secrets for GIT_USER_NAME or GIT_PAT missing, please register them with access to this runner"
echo "*Note, Organisation secrets are not accessible to Forked repos and need registering in the local fork"
exit 1
}
echo "---------------------------------------------"
echo "Read dependancy input values as json"
$JSONdependencies = $dependencies | ConvertFrom-Json
echo $JSONdependencies
# Read current Manifest json
$manifestPath = $destinationPath + $directorySeparatorChar + 'manifest.json'
$projectManifest = Get-Content -Path $manifestPath | ConvertFrom-Json
$strArray = $projectManifest.dependencies.PsObject.Properties | ForEach-Object {"$($_.Name)@$($_.Value),"}
echo "---------------------------------------------"
echo "Loop through new dependancies and add them to the project Manifest"
foreach($dependency in $JSONdependencies){
$dependency.PsObject.Properties | ForEach-Object -Process {
$dependencyName = $_.Name
$dependencyPath = $dependencyName.Replace("/","_")
$dependencyURL = $_.Value
echo "---------------------------------------------"
echo "Cloning dependency - Name [$dependencyName] - Path [$dependencyPath] - URL [$dependencyURL]"
$cloneURL = "https://${{ secrets.GIT_USER_NAME }}:${{ secrets.GIT_PAT }}@$dependencyURL"
echo "cloning $dependencyName from $dependencyURL and moving to $destinationPath"
echo "git path - $cloneURL"
# Clone Dependancy repo to destination folder
git clone -b $dependencyName --single-branch $cloneURL $dependencyPath
if( -not (Test-Path -Path "$dependencyPath")){
echo "Unable to clone $dependencyName from $dependencyURL"
exit 1
}
# Move files from clone path into packages folder, if the dependency contains a UPM package then move the entire folder and not just its contents
if (Test-Path -Path "$dependencyPath/package.json") {
$package_json = Get-Content -Path $dependencyPath/package.json | ConvertFrom-Json
$packageName = $package_json.name
Rename-Item $dependencyPath $packageName
echo "Moving whole $packageName UPM package to $destinationPath"
Move-Item -Path "$packageName" -Destination $destinationPath
}
else {
echo "Moving the contents of $dependencyName into the $destinationPath folder"
Move-Item -Path "$dependencyPath/*" -Destination $destinationPath
}
# Get Dependency manifest entries (if applicable)
if (Test-Path -Path "$destinationPath/$dependencyName.json") {
$dependencyManifest = Get-Content -Path "$destinationPath/$dependencyName.json" | ConvertFrom-Json
$dependencyManifest.dependencies.PsObject.Properties | ForEach-Object {
$strArray += "$($_.Name)@$($_.Value),"
}
}
else{
echo "No denendency json found called $destinationPath/$dependencyName.json, skipping adding additional manifest entries"
}
}
}
echo "---------------------------------------------"
# Reformat combined dependancies list
$strArray = $strArray.Trim(",") | ConvertTo-Json
$strArray = $strArray.Replace("@",'":"').Replace("[","{").Replace("]","}")
$strArrayObject = $strArray | ConvertFrom-Json
# Save manifest back to project
$projectManifest.dependencies = $strArrayObject
$projectManifest | ConvertTo-Json | Set-Content -Path "$destinationPath/manifest.json"
echo "Project updated with the following dependencies"
echo "-----------------------------------------------"
echo $projectManifest
}
echo "::endgroup::"
echo "::group::Run build"
echo "---------------------------------------------"
echo "Start Testing"
echo "Unity Command\n[unity-editor -projectPath $TempUnityProjectName -logfile $logPath -batchmode -nographics -quit -buildTarget ${{ matrix.build-target }}]"
unity-editor -projectPath $TempUnityProjectName -logfile $logPath -batchmode -nographics -quit -buildTarget ${{ matrix.build-target }}
echo "---------------------------------------------"
echo "::group::Unity Unit tests Results"
if (Test-Path $testsLogPath) {
echo "Test Run results for ${GITHUB_REPOSITORY} Branch ${GITHUB_REF}"
echo ""
Select-Xml -Path $testsLogPath -XPath '/test-run/test-suite' | ForEach-Object { "Name: " +$_.Node.name, ", Result: " + $_.Node.result, ", Total Tests: " + $_.Node.total, ", Passed: " + $_.Node.passed, ", Failed: " + $_.Node.failed, ", Skipped: " + $_.Node.skipped }
}
else {
echo "No test results found for ${GITHUB_REPOSITORY} Branch ${GITHUB_REF} at $testsLogPath"
echo ""
}
echo "::endgroup::"
if($LASTEXITCODE -ne '0'){
echo "::group::Unity Unit tests errors"
$exitCode = $testResult.ExitCode
Get-Content $logPath
echo "Build failed due to errors ($LASTEXITCODE), please check the log at $logPath"
echo "::endgroup::"
exit $LASTEXITCODE
}
echo "::endgroup::"
shell: pwsh
- uses: actions/upload-artifact@v3
if: always()
with:
name: unity-build-log
path: Logs/**

146
.github/workflows/tagrelease.yml vendored Normal file
View File

@ -0,0 +1,146 @@
name: Package UPM project and deploy
on:
workflow_call:
inputs:
build-target:
required: true
type: string
build-type:
required: false
default: 'pre-release'
type: string
# options:
# - major
# - minor
# - patch
# - pre-release
# - build
outputs:
packageversion:
description: "Returns the version of Unity the UPM package requires"
value: ${{ jobs.packageRelease.outputs.packageversion }}
secrets:
GIT_USER_NAME:
required: false
jobs:
packageRelease:
name: Package UPM Project and tag
runs-on: ${{ inputs.build-target }}
outputs:
packageversion: ${{ steps.getpackageversion.outputs.packageversion }}
steps:
- name: Script Version
run: |
echo "::group::Script Versioning"
$scriptVersion = "1.0.2"
echo "Build Script Version: $scriptVersion"
echo "::endgroup::"
shell: pwsh
- uses: actions/checkout@v3
with:
submodules: recursive
clean: true
token: ${{ secrets.GIT_PAT }}
- uses: actions/setup-node@v3
- name: Set Github vars
run: |
if([string]::IsNullOrEmpty('${{ secrets.GIT_USER_NAME }}')){
if([string]::IsNullOrEmpty('${{ secrets.GIT_USER_NAME }}')){
$gitUser = "action"
$gitEmail = "action@github.com"
}
else {
$gitUser = "${GITHUB_ACTOR}"
$gitEmail = "$gitUser@users.noreply.github.com"
}
}
else {
$gitUser = "${{ secrets.GIT_USER_NAME }}"
$gitEmail = "$gitUser@users.noreply.github.com"
}
echo "email $gitUser@users.noreply.github.com"
git config --global user.email "$gitUser@users.noreply.github.com"
git config --global user.name "$gitUser"
shell: pwsh
- id: getpackageversion
name: Bump UPM Package version
run: |
function UpdateProjectVersionJSON {
param (
[Parameter(Mandatory)]
$type,
$packageFile = 'package.json'
)
<#
Type of build can be one of the following
- 'build' # Build release - 1.0.0-pre-release.0+1
- 'pre-release' # Pre-Release release - 1.0.0-pre-release.1
- 'patch' # Patch release - 1.0.1
- 'minor' # Minor release - 1.1.0
- 'major' # Major release - 2.0.0
#>
if ( -not (Test-Path -Path $packageFile) ) {
Write-Error "Failed to find a valid project manifest at `"$packageFile`""
return $null
}
$packageInfo = (Get-Content $packageFile -Raw) | ConvertFrom-Json
Write-Host "Detected Project Version:" $packageInfo.version
function IfNull($a, $b, $c) { if ($null -eq $a) { return $b } else { return $c } }
$packageSemVer = [System.Management.Automation.SemanticVersion]$packageInfo.version
$majorVersion = if($null -eq $packageSemVer.Major) {0} else {$packageSemVer.Major}
$minorVersion = if($null -eq $packageSemVer.Minor) {0} else {$packageSemVer.Minor}
$patchVersion = if($null -eq $packageSemVer.Patch) {0} else {$packageSemVer.Patch}
$prereleaseVersion = if($null -eq $packageSemVer.PreReleaseLabel) {0} else {$packageSemVer.PreReleaseLabel.Replace('pre-release.','')}
$buildVersion = if($null -eq $packageSemVer.BuildLabel) {0} else {$packageSemVer.BuildLabel}
# work out new version
switch ($type) {
'build' {
[int]$buildVersion += 1
$newPackageSemVer = [System.Management.Automation.SemanticVersion]::New($majorVersion, $minorVersion, $patchVersion, "pre-release." + $prereleaseVersion, $buildVersion)
}
'pre-release' {
[int]$prereleaseVersion += 1
$newPackageSemVer = [System.Management.Automation.SemanticVersion]::New($majorVersion, $minorVersion, $patchVersion, "pre-release." + $prereleaseVersion)
}
'patch' {
[int]$patchVersion += 1
$newPackageSemVer = [System.Management.Automation.SemanticVersion]::New($majorVersion, $minorVersion, $patchVersion)
}
'minor' {
[int]$minorVersion += 1
$newPackageSemVer = [System.Management.Automation.SemanticVersion]::New($majorVersion, $minorVersion, 0)
}
'major' {
[int]$majorVersion += 1
$newPackageSemVer = [System.Management.Automation.SemanticVersion]::New($majorVersion, 0, 0)
}
}
Write-Host "Upgrading project version [$packageSemVer] to [$newPackageSemVer]"
# Write out updated package info
$packageInfo.version = $newPackageSemVer.ToString()
$packageInfo | ConvertTo-Json | Set-Content $packageFile
return $packageInfo.version
}
$packageFile = 'package.json'
$result = UpdateProjectVersionJSON("${{ inputs.build-type }}","$packageFile")
if([string]::IsNullOrEmpty($result)) {
echo "Version patch failed"
exit 1
}
echo "packageversion=$result" >> $env:GITHUB_OUTPUT
git add "$packageFile"
git commit -m "Auto increment pre-release version to $result [skip ci]"
git tag -fa "$result" "${GITHUB_SHA}" -m "$result Release"
git push origin --force
shell: pwsh

3
.gitmodules vendored
View File

@ -1,4 +1,3 @@
[submodule "Examples~"]
path = Examples~
url = https://SimonDarksideJ@bitbucket.org/UnityUIExtensions/unity-ui-extensions.git
branch = Examples
url = https://github.com/Unity-UI-Extensions/com.unity.uiextensions-examples.git

View File

@ -35,6 +35,4 @@ sysinfo.txt
/.vs
*.gitmodules
# NPM publish exclusions
bitbucket-pipelines.yml
bitbucket-pipelines.yml.meta
**/.github/*

View File

@ -4,74 +4,117 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
## 2019.6 - 2.5 - Bug squash - 2021/05/10
## Release 2.3 - Reanimation - 2022/02/07
Its been a while since the last update and although Unity keeps changing, thankfully the parts underneath do not. THanks to some awesome work by our contributors and the test teams, we made a run on some underlying bugs and issues. If you spot anything else, please log it on the BitBucket site for resolution.
It has been a tough time for all since the last update, but things have been moving steadily along. In the past few months there has been a concerted effort to revamp and update the project ready for Unity 2022, as well as migrating the source repository over to GitHub and refreshing all the things.
We hope the new release is better for everyone and we have paid close attention to the editor menus and places to find all the controls for this release.
> Be sure to logon to the new [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project, if you have any questions, queries or suggestions
To get up to speed with the Unity UI Extensions, check out the [Getting Started](https://unity-ui-extensions.github.io/GettingStarted.html) Page.
> Ways to get in touch:
>
> - [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project
> - [GitHub Discussions](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions), if you have any questions, queries or suggestions
>
> Much easier that posting a question / issue on YouTube, Twitter or Facebook :D
>
> ## [UIExtensions Gitter Channel](https://gitter.im/Unity-UI-Extensions/Lobby)
## Breaking changes
### Added
For customers upgrading from earlier versions of Unity to Unity 2020, please be aware of the Breaking change related to Text Based components. You will need to manually replace any UI using the older ```Text``` component and replace them with ```TextMeshPro``` versions. This is unavoidable due to Unity deprecating the Text component.
Nothing new this time, bugfix release.
> New users to 2022 are unaffected as all the Editor commands have been updated to use the newer TextMeshPro versions.
### Changed
For more details, see the [deprecation notice](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions/428) on GitHub.
- Updated UI Line connector to use relative position instead of anchored position to verify if the Lines need updating.
- Allow menu prefabs to not have to have canvas components. This allows you to use any type of prefab as a "menu". Adam Kapos mentions the concept on the Unite talk, https://youtu.be/wbmjturGbAQ?t=1654
- Updated segment line drawing for Line Lists. Seems Unity no longer needs UV's to be wrapped manually.
- Updated the AutoCompleteComboBox to display text as entered (instead of all lowercase)
- Updated the ComboBox to display text as entered (instead of all lowercase)
- Updated ComboBox Examples to include programmatic versions
- Further ComboBox improvements including:
* Upwards panel
* Start fixes
* Item Template resize
* Disabled sorting on combobox as it wasn't working
* Disabled Slider handle when not in use
* Updated Example
- Updated the new Input system switch and tested against 2021
## Added
### Deprecated
- Added new FIFO based UI Line Render when dynamic line rendering is needed.
- Added ResetSelectableHighlight component.
- Added SetArc method to UICircle as requested.
- Added new UIHorizontalScroller based on UIVerticalScroller.
- Added OnHighlightChanged and OnPressChanged events for UI Button.
- Added error handling around setting Unity UI Components for Vertical/Horizontal ScrollSnaps.
- Added Editor Menu Option to create a Min/Max slider.
- Added the ability to set a specific item for combobox controls on start and not just the first.
- Added the ability to disable the combo boxes and make them read-only.
None
## Changed
### Fixed
- Refresh FancyScrollView with the latest fixes
- All Text based components updated to use TextMeshPro from Unity 2022 **Breaking Change**
- Reordering issue resolved with ScrollRectOcclusion.
- Fixed Sorting at min and max positions for ScrollRect
- Updated ScrollToSelect script provided by zero3growlithe, tested and vastly reduces the previous jitter. Still present but barely noticeable now.
- Fixed Issue # 363 Update Combobox control that takes multiple items programmatically, to only allow distinct items
- Fixed the issues where dragging outside the range slider handle causes the range to update. - Resolves #369
- Resolves an issue with Unity putting the previous controls vertex array in an uninitialised control.
- Applied J.R. Mitchell's fix for the Accordion Controls/Accordion/AccordionElement.cs - resolves: #364
- Resolved issue where the Content Scroll snap issue with only 1 child. Resolves #362
- Updated the PaginationManager to override if the ScrollSnap is in motion.
- Clean-up and reset pivots on scene start.
- Merged in feature/improved-ui-highlightable (pull request UILineRenderer - issues with specifying point locations at runtime #123).
- Merged in fix/rangesliderfix (pull request HorizontalScrollSnap Mask Area doesn't work when content created dynamically #125).
- Merged in fix/infinitescrollcontentsize (pull request Gradient initialization should be in Awake() #126).
- Merged in feature/controlTouchUp (pull request UILineRenderer mesh not updating in Editor scene view #127).
- Upgraded RangeSlider to work in both Horizontal and Vertical setups.
- Merged in RangeSlider-upgrade. (pull request Newtonsoft.Json.dll conflict #131)
- Updated UIVertical scroller to be 2022 compliant.
- Updated Curly UI to wait until end of the frame to recalculate positions.
- Updated Depth Texture sampler in UI Particles Shaders.
- Updated Points to always be an array of 1 when set to nothing for the Line Renderer.
- Updated Cooldown button to work with Keyboard input.
- Removed unneeded size calculation which caused some issues with mixed content.
- Resolved an issue whereby the last row in a flow layout group would not size correctly.
- Updated all components using "LayoutGroup" to override their OnDisable.
- Updated validation in the new MinMaxSlider.
- Updated Editor create options to add the correct Event System Input manager.
- Updated initialisation logic to not cause an endless loop in the TabNavigationHelper.
- Updated "Action" use to "UnityAction" to avoid Unity issues for DropDowns.
- Updated UIVerticalScroller for standards.
- Updated ReorderableList/ReorderableListElement to prevent creating a fake object for non-transferable items.
- Updated panel drawing for ComboBox controls and added DropdownOffset.
- Updated build issue with ReorderableListElement.
- Updated NonDrawingGraphic to require a CanvasRender, else it causes an error on run.
### Removed
## Deprecated
None
- Marked ScrollPositionController as Obsolete, users should use the new Scoller.
- BestFitOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- NicerOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- Marked TileSizeFitter as obsolete as Unity has made this unworkable.
### Additional Notes
## Fixed
#### [Installation Instructions](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
- Resolved issues with DisplayAbove and using a 0 ItemsToDisplay for ComboBox controls.
- Resolved startup issue that prevented the control from being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes.
- Patch fix for UILineRenderer.
- Resolves issue where the lower range value would become stuck when moving.
- Updated Infinite scroll to work with content of different sizes.
- Updated Dropdown list to NOT resize text Rect on draw.
- Revised the Curly UI fix as it was preventing the graphic from being updated in the scene view.
- Cleanup and ensuring the UIParticleSystem is disposed in onDestroy correctly.
- Clean up range slider unused variables.
As of Unity 2019, there are now two paths for getting access to the Unity UI Extensions project:
## Additional Notes
### [Installation Instructions](https://unity-ui-extensions.github.io/UPMInstallation.html)
- Unity 2019 or higher
The recommended way to add the Unity UI Extensions project to your solution is to use the Unity package Manager. Simply use the Unity Package Manager to reference the project to install it
Alternatively, you can also use the pre-compiled Unity packages if you wish, however, UPM offers full versioning support to allow you to switch versions as you wish.
New for 2020, we have added OpenUPM support and the package can be installed using the following [OpenUPM CLI](https://openupm.com/docs/) command:
```cli
`openupm add com.unity.uiextensions`
```
> For more details on using [OpenUPM CLI, check the docs here](https://github.com/openupm/openupm-cli#installation).
- Unity Package Manager - manual
Alternatively, you can also add the package manually through the Unity package manager using the scope ```com.unity.uiextensions```, see the [Unity Package Manager docs](https://learn.unity.com/tutorial/the-package-manager) for more information.
- Unity 2018 or lower
The pre-compiled Unity assets are the only solution for Unity 2018 or earlier due to the changes in the Unity UI framework in Unity made for 2019.
Either clone / download this repository to your machine and then copy the scripts in, or use the pre-packaged .UnityPackage for your version of Unity and import it as a custom package in to your project.
#### Upgrade Notes
### Upgrade Notes
### UPM
If you are using UPM to gain access to the Unity UI Extensions, then you only need to update to the latest version in the Package Manager, no other changes needed.
### Customers using the .UnityPackage
Due to the restructure of the package to meet Unity's new package guidelines, we recommend **Deleting the current Unity UI Extensions** folder prior to importing the new package.

View File

@ -5,17 +5,20 @@
The Unity UI Extensions project is a collection of extension scripts/effects and controls to enhance your Unity UI experience. This includes over 70+ controls, utilities, effects and some much-needed love to make the most out of the Unity UI system (formally uGUI) in Unity.
[Check out our Tumblr page for a sneak peek](https://www.tumblr.com/blog/unityuiextensions)
> Contact the UI Extensions Team
> Be sure to logon to the new [Gitter Chat site](https://gitter.im/Unity-UI-Extensions/Lobby) for the UI Extensions project, if you have any questions, queries or suggestions
> Much easier than posting a question / issue on [YouTube](http://www.youtube.com/c/UnityUIExtensions), [Twitter](https://twitter.com/hashtag/UnityUIExtensions) or [Facebook](https://www.facebook.com/UnityUIExtensions) :D
You can follow the UI Extensions team for updates and news on:
### [Twitter - #unityuiextensions](https://twitter.com/search?q=%23unityuiextensions) / [Facebook](https://www.facebook.com/UnityUIExtensions/) / [YouTube](https://www.youtube.com/@UnityUIExtensions)
> Ways to get in touch:
>
> [**UIExtensions Gitter Chanel**](https://gitter.im/Unity-UI-Extensions/Lobby)
> - [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project
> - [GitHub Discussions](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions), if you have any questions, queries or suggestions
# Installing Unity UI Extensions
To install this package, follow the instructions in the Package Manager documentation.
For more details on [Getting Started](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted) please checkout the [online documentation here](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted).
For more details on [Getting Started](https://unity-ui-extensions.github.io/GettingStarted) please checkout the [online documentation here](https://unity-ui-extensions.github.io/).
# Using Unity UI Extensions
@ -23,7 +26,7 @@ The UI Extensions project provides many automated functions to add the various c
Some of the features are also available through the GameObject "Add Component" menu in the inspector.
For a full list of the controls and how they are used, please see the [online documentation](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls) for the project.
For a full list of the controls and how they are used, please see the [online documentation](https://unity-ui-extensions.github.io/Controls.html) for the project.
# Technical details
@ -31,64 +34,102 @@ For a full list of the controls and how they are used, please see the [online do
This version of the Unity UI Extensions is compatible with the following versions of the Unity Editor:
- 2019 and above - the recommended path for 2019+ is to use the Unity Package Manager to get access to the package. Full details for installing via UPM can be [found here](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/UPMInstallation).
- 2019 and above - the recommended path for 2019+ is to use the Unity Package Manager to get access to the package. Full details for installing via UPM can be [found here](https://unity-ui-extensions.github.io/UPMInstallation.html).
> Alternatively, the Asset packages have been tested to work with 2019 as well if you prefer to install that way.
- 2018 and below - for 2018 and use this package, you will have to import the asset package(s), either from the Asset Store or from the alternate download locations [listed here](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads).
- 2018 and below - for 2018 and use this package, you will have to import the asset package(s), either from the Asset Store or from the alternate download locations [listed here](https://unity-ui-extensions.github.io/Downloads).
## [Release Notes](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ReleaseNotes/RELEASENOTES)
## [Release Notes](https://unity-ui-extensions.github.io/ReleaseNotes/RELEASENOTES)
### 2019.5 - 2.3 - Accelerated Deployment
## Release 2.3 - Reanimation - 2022/02/07
#### Added
It has been a tough time for all since the last update, but things have been moving steadily along. In the past few months there has been a concerted effort to revamp and update the project ready for Unity 2022, as well as migrating the source repository over to GitHub and refreshing all the things.
We hope the new release is better for everyone and we have paid close attention to the editor menus and places to find all the controls for this release.
- Add squircle primitive
- Adding new magnetic scroll control
- Added a static library to collate shaders on first use.
- Finalized new InputManagerHelper, which translates input based on the operating input system, new or old Updated CardStack2D to have defined keyboard input or specific gamepad input over the older axisname for new input system.
- Updated DropDown and Autocomplete controls based on feedback in #204
To get up to speed with the Unity UI Extensions, check out the [Getting Started](https://unity-ui-extensions.github.io/GettingStarted.html) Page.
#### Changed
> Ways to get in touch:
>
> - [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project
> - [GitHub Discussions](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions), if you have any questions, queries or suggestions
>
> Much easier that posting a question / issue on YouTube, Twitter or Facebook :D
- Examples now included with UPM delivery and available as a button on the UPM package manager window
- Updated DropDown and Autocomplete controls based on feedback in #204
- Updated Accordion to support both Vertical as well as Horizontal layout
- Updated ComboBox controls to improve better programmatic controls
- Updates to the Infinite scroll to support content of various sizes
- Updated UI Knob control - enabled dragging outside the target area, added example scene
- Minor update to MagneticInfinite Scroll
- Refactored and extended the ContentScrollSnap control
- Added protection against errors and empty scrollrect content
- Added new SetNewItems function to add children programmatically to the control and reset accordingly
- Patch supplied by a contributor to improve the texture sheet use with the UIParticlesystem
- Added "SetKnobValue" function which allows the setting of Value and loops
- Added the programmatic capability to change the parent scroll rect on the ScrollConflictManager at runtime.
## Breaking changes
#### Deprecated
For customers upgrading from earlier versions of Unity to Unity 2020, please be aware of the Breaking change related to Text Based components. You will need to manually replace any UI using the older ```Text``` component and replace them with ```TextMeshPro``` versions. This is unavoidable due to Unity deprecating the Text component.
None
> New users to 2022 are unaffected as all the Editor commands have been updated to use the newer TextMeshPro versions.
#### Fixed
For more details, see the [deprecation notice](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions/428) on GitHub.
- Fix to add a "RequireComponent" to Primitives as Unity 2020 does not add them by default
- Remove old Examples submodule
- Updated submodules to hide Examples folder Additionally, updated Package manifest to allow importing of examples direct from UPM package.
- Fixed hard swipe to ensure it only ever moves one page, no matter how far you swipe.
- Fixed a conflict when using the ScrollConflictManager in child content of a HSS or VSS
- Fix for UI Particle system looping
- Fixed public GoToScreen call to only raise events internally (not multiple)
- Final roll-up and fix. Resolved race condition for associated pagination controls.
- Fixed issue with page events not being raised when inertia was disabled (velocity was always zero)
- When cloned, reorderable list was creating a second List Content component that was not initialized. Refactored to ensure only one list content was present and is initialized correctly
- Reorderable list items marked as transferable, remain transferable after being dropped
- Patch to resolve issues without the new Input System installed
- Refined magnetic scroll and dependencies while documenting Updated example
- Patch Tooltip
## Added
#### Removed
- Added new FIFO based UI Line Render when dynamic line rendering is needed.
- Added ResetSelectableHighlight component.
- Added SetArc method to UICircle as requested.
- Added new UIHorizontalScroller based on UIVerticalScroller.
- Added OnHighlightChanged and OnPressChanged events for UI Button.
- Added error handling around setting Unity UI Components for Vertical/Horizontal ScrollSnaps.
- Added Editor Menu Option to create a Min/Max slider.
- Added the ability to set a specific item for combobox controls on start and not just the first.
- Added the ability to disable the combo boxes and make them read-only.
None
## Changed
- Refresh FancyScrollView with the latest fixes
- All Text based components updated to use TextMeshPro from Unity 2022 **Breaking Change**
- Clean-up and reset pivots on scene start.
- Merged in feature/improved-ui-highlightable (pull request UILineRenderer - issues with specifying point locations at runtime #123).
- Merged in fix/ragesliderfix (pull request HorizontalScrollSnap Mask Area doesn't work when content created dynamically #125).
- Merged in fix/infinitescrollcontentsize (pull request Gradient initialization should be in Awake() #126).
- Merged in feature/controlTouchUp (pull request UILineRenderer mesh not updating in Editor scene view #127).
- Upgraded RangeSlider to work in both Horizontal and Vertical setups.
- Merged in RangeSlider-upgrade. (pull request Newtonsoft.Json.dll conflict #131)
- Updated UIVertical scroller to be 2022 compliant.
- Updated Curly UI to wait until end of the frame to recalculate positions.
- Updated Depth Texture sampler in UI Particles Shaders.
- Updated Points to always be an array of 1 when set to nothing for the Line Renderer.
- Updated Cooldown button to work with Keyboard input.
- Removed unneeded size calculation which caused some issues with mixed content.
- Resolved an issue whereby the last row in a flow layout group would not size correctly.
- Updated all components using "LayoutGroup" to override their OnDisable.
- Updated validation in the new MinMaxSlider.
- Updated Editor create options to add the correct Event System Input manager.
- Updated initialisation logic to not cause an endless loop in the TabNavigationHelper.
- Updated "Action" use to "UnityAction" to avoid Unity issues for DropDowns.
- Updated UIVerticalScroller for standards.
- Updated ReorderableList/ReorderableListElement to prevent creating a fake object for non-transferable items.
- Updated panel drawing for ComboBox controls and added DropdownOffset.
- Updated build issue with ReorderableListElement.
- Updated NonDrawingGraphic to require a CanvasRender, else it causes an error on run.
## Deprecated
- Marked ScrollPositionController as Obsolete, users should use the new Scoller.
- BestFitOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- NicerOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- Marked TileSizeFitter as obsolete as Unity has made this unworkable.
## Fixed
- Resolved issues with DisplayAbove and using a 0 ItemsToDisplay for ComboBox controls.
- Resolved startup issue that prevented the control from being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes.
- Patch fix for UILineRenderer.
- Resolves issue where the lower range value would become stuck when moving.
- Updated Infinite scroll to work with content of different sizes.
- Updated Dropdown list to NOT resize text Rect on draw.
- Revised the Curly UI fix as it was preventing the graphic from being updated in the scene view.
- Cleanup and ensuring the UIParticleSystem is disposed in onDestroy correctly.
- Clean up range slider unused variables.
- [UI Extensions Issue log](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues)
## Upgrade Notes
We recommend using the UPM delivery method. If you are using the Unity asset, there should be no issues updating but if you have a problem, just deleted the old Unity-UI-Extensions folder and import the asset new.
# Document revision history
@ -98,3 +139,4 @@ None
|September 3rd, 2019|2019.1 (v2.1) released, First major update for the 2.0 series.|
|August 8th, 2020|2019.4 (v2.2) released, New UPM Delivery.|
|October 10th, 2020|2019.5 (v2.2) released, New UPM fast delivery|
|February 7th, 2022|v2.3 released, New Home, UPM fast delivery via OpenUPM|

View File

@ -1,12 +1,11 @@
fileFormatVersion: 2
guid: 8701e045b26e51f4eb345f2ccb3c13f5
timeCreated: 1426804458
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: c1047f9974e7ee1478bbf5490a7a62d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -68,7 +68,12 @@ namespace UnityEngine.UI.Extensions
Handles.color = Color.gray;
EditorGUI.BeginChangeCheck();
#if UNITY_2022_1_OR_NEWER
Vector3 newCornerPos = Handles.FreeMoveHandle(script.transform.TransformPoint(cornerPos), HandleUtility.GetHandleSize(script.transform.TransformPoint(cornerPos)) / 7, Vector3.one, Handles.SphereHandleCap);
#else
Vector3 newCornerPos = Handles.FreeMoveHandle(script.transform.TransformPoint(cornerPos), script.transform.rotation, HandleUtility.GetHandleSize(script.transform.TransformPoint(cornerPos)) / 7, Vector3.one, Handles.SphereHandleCap);
#endif
Handles.Label(newCornerPos, string.Format("Corner Mover"));
newCornerPos = script.transform.InverseTransformPoint(newCornerPos);

View File

@ -4,8 +4,6 @@
using UnityEditor;
using UnityEditor.AnimatedValues;
// For maintenance, every new [SerializeField] variable in Scroller must be declared here
namespace UnityEngine.UI.Extensions
{
[CustomEditor(typeof(Scroller))]
@ -20,16 +18,11 @@ namespace UnityEngine.UI.Extensions
SerializedProperty inertia;
SerializedProperty decelerationRate;
SerializedProperty snap;
SerializedProperty snapEnable;
SerializedProperty snapVelocityThreshold;
SerializedProperty snapDuration;
SerializedProperty snapEasing;
SerializedProperty draggable;
SerializedProperty scrollbar;
AnimBool showElasticity;
AnimBool showInertiaRelatedValues;
AnimBool showSnapEnableRelatedValues;
void OnEnable()
{
@ -41,16 +34,11 @@ namespace UnityEngine.UI.Extensions
inertia = serializedObject.FindProperty("inertia");
decelerationRate = serializedObject.FindProperty("decelerationRate");
snap = serializedObject.FindProperty("snap");
snapEnable = serializedObject.FindProperty("snap.Enable");
snapVelocityThreshold = serializedObject.FindProperty("snap.VelocityThreshold");
snapDuration = serializedObject.FindProperty("snap.Duration");
snapEasing = serializedObject.FindProperty("snap.Easing");
draggable = serializedObject.FindProperty("draggable");
scrollbar = serializedObject.FindProperty("scrollbar");
showElasticity = new AnimBool(Repaint);
showInertiaRelatedValues = new AnimBool(Repaint);
showSnapEnableRelatedValues = new AnimBool(Repaint);
SetAnimBools(true);
}
@ -58,14 +46,12 @@ namespace UnityEngine.UI.Extensions
{
showElasticity.valueChanged.RemoveListener(Repaint);
showInertiaRelatedValues.valueChanged.RemoveListener(Repaint);
showSnapEnableRelatedValues.valueChanged.RemoveListener(Repaint);
}
void SetAnimBools(bool instant)
{
SetAnimBool(showElasticity, !movementType.hasMultipleDifferentValues && movementType.enumValueIndex == (int)MovementType.Elastic, instant);
SetAnimBool(showInertiaRelatedValues, !inertia.hasMultipleDifferentValues && inertia.boolValue, instant);
SetAnimBool(showSnapEnableRelatedValues, !snapEnable.hasMultipleDifferentValues && snapEnable.boolValue, instant);
}
void SetAnimBool(AnimBool a, bool value, bool instant)
@ -126,31 +112,6 @@ namespace UnityEngine.UI.Extensions
{
EditorGUILayout.PropertyField(decelerationRate);
EditorGUILayout.PropertyField(snap);
using (new EditorGUI.IndentLevelScope())
{
DrawSnapRelatedValues();
}
}
}
}
void DrawSnapRelatedValues()
{
if (snap.isExpanded)
{
EditorGUILayout.PropertyField(snapEnable);
using (var group = new EditorGUILayout.FadeGroupScope(showSnapEnableRelatedValues.faded))
{
if (!group.visible)
{
return;
}
EditorGUILayout.PropertyField(snapVelocityThreshold);
EditorGUILayout.PropertyField(snapDuration);
EditorGUILayout.PropertyField(snapEasing);
}
}
}

View File

@ -0,0 +1,121 @@
///Credit brogan89
///Sourced from - https://github.com/brogan89/MinMaxSlider
using System;
using UnityEditor;
using UnityEditor.UI;
namespace UnityEngine.UI.Extensions
{
[CustomEditor(typeof(MinMaxSlider), true)]
[CanEditMultipleObjects]
public class MinMaxSliderEditor : SelectableEditor
{
private SerializedProperty _customCamera;
private SerializedProperty _sliderBounds;
private SerializedProperty _minHandle;
private SerializedProperty _maxHandle;
private SerializedProperty _minText;
private SerializedProperty _maxText;
private SerializedProperty _textFormat;
private SerializedProperty _middleGraphic;
private SerializedProperty _minLimit;
private SerializedProperty _maxLimit;
private SerializedProperty _wholeNumbers;
private SerializedProperty _minValue;
private SerializedProperty _maxValue;
private SerializedProperty _onValueChanged;
private readonly GUIContent label = new GUIContent("Min Max Values");
protected override void OnEnable()
{
base.OnEnable();
_customCamera = serializedObject.FindProperty("customCamera");
_sliderBounds = serializedObject.FindProperty("sliderBounds");
_minHandle = serializedObject.FindProperty("minHandle");
_maxHandle = serializedObject.FindProperty("maxHandle");
_minText = serializedObject.FindProperty("minText");
_maxText = serializedObject.FindProperty("maxText");
_textFormat = serializedObject.FindProperty("textFormat");
_middleGraphic = serializedObject.FindProperty("middleGraphic");
_minLimit = serializedObject.FindProperty("minLimit");
_maxLimit = serializedObject.FindProperty("maxLimit");
_wholeNumbers = serializedObject.FindProperty("wholeNumbers");
_minValue = serializedObject.FindProperty("minValue");
_maxValue = serializedObject.FindProperty("maxValue");
_onValueChanged = serializedObject.FindProperty("onValueChanged");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
serializedObject.Update();
float minLimitOld = _minLimit.floatValue;
float maxLimitOld = _maxLimit.floatValue;
float minValueOld = _minValue.floatValue;
float maxValueOld = _maxValue.floatValue;
EditorGUILayout.PropertyField(_customCamera);
EditorGUILayout.PropertyField(_sliderBounds);
EditorGUILayout.PropertyField(_minHandle);
EditorGUILayout.PropertyField(_maxHandle);
EditorGUILayout.PropertyField(_middleGraphic);
EditorGUILayout.PropertyField(_minText);
EditorGUILayout.PropertyField(_maxText);
EditorGUILayout.PropertyField(_textFormat);
EditorGUILayout.PropertyField(_minLimit);
EditorGUILayout.PropertyField(_maxLimit);
EditorGUILayout.PropertyField(_wholeNumbers);
EditorGUILayout.PropertyField(_minValue);
EditorGUILayout.PropertyField(_maxValue);
float minValue = Mathf.Clamp(_minValue.floatValue, _minLimit.floatValue, _maxLimit.floatValue);
float maxValue = Mathf.Clamp(_maxValue.floatValue, _minLimit.floatValue, _maxLimit.floatValue);
EditorGUILayout.MinMaxSlider(label, ref minValue, ref maxValue, _minLimit.floatValue, _maxLimit.floatValue);
bool anyValueChanged = !IsEqualFloat(minValueOld, minValue)
|| !IsEqualFloat(maxValueOld, maxValue)
|| !IsEqualFloat(minLimitOld, _minLimit.floatValue)
|| !IsEqualFloat(maxLimitOld, _maxLimit.floatValue);
if (anyValueChanged)
{
MinMaxSlider slider = (MinMaxSlider)target;
// force limits to ints if whole numbers.
// needed to do this here because it wouldn't set in component script for some reason
if (slider.wholeNumbers)
{
_minLimit.floatValue = Mathf.RoundToInt(_minLimit.floatValue);
_maxLimit.floatValue = Mathf.RoundToInt(_maxLimit.floatValue);
}
// set slider values
slider.SetValues(minValue, maxValue, _minLimit.floatValue, _maxLimit.floatValue);
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_onValueChanged);
serializedObject.ApplyModifiedProperties();
}
/// <summary>
/// Returns true if floating point numbers are within 0.01f (close enough to be considered equal)
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
private static bool IsEqualFloat(float a, float b)
{
return Math.Abs(a - b) < 0.01f;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 69352ed1561021b48ac258f81f48a988
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,10 +3,12 @@
// For maintenance, every new [SerializeField] variable in ScrollPositionController must be declared here
using System;
using UnityEditor;
namespace UnityEngine.UI.Extensions
{
[Obsolete("ScrollPositionController has been replaced by the Scroller component", true)]
[CustomEditor(typeof(ScrollPositionController))]
[CanEditMultipleObjects]
public class ScrollPositionControllerEditor : Editor

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
{
"name": "UnityUIExtensions.editor",
"rootNamespace": "",
"references": [
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
"GUID:2bafac87e7f4b9b418d9448d219b01ab",
"GUID:cf414061cae3a954baf92763590f3127"
"GUID:cf414061cae3a954baf92763590f3127",
"GUID:6055be8ebefd69e48b49212b09b47b2f",
"GUID:75469ad4d38634e559750d17036d5f7c"
],
"includePlatforms": [
"Editor"
@ -14,5 +17,6 @@
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": []
"versionDefines": [],
"noEngineReferences": false
}

@ -1 +1 @@
Subproject commit d08257d62c3c95771540f51f77f50a491715d3b7
Subproject commit 774bde78bf8792ad8de1c96ad7e874932fd716d7

244
README.md
View File

@ -1,10 +1,10 @@
# Unity UI Extensions README
This is an extension project for the new Unity UI system which can be found at: [Unity UI Source](https://bitbucket.org/Unity-Technologies/ui)
This is an extension project for the new Unity UI system which can be found at: [Unity UI Source](https://github.com/Unity-Technologies/uGUI)
> [Check out the control demos on our Tumblr page](https://unityuiextensions.tumblr.com/)
## [Intro](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
## [Intro](https://unity-ui-extensions.github.io/GettingStarted)
For more info, here's a little introduction video for the project:
@ -12,15 +12,16 @@ For more info, here's a little introduction video for the project:
You can follow the UI Extensions team for updates and news on:
### [Twitter](https://twitter.com/hashtag/UnityUIExtensions?src=hash) / [Facebook](https://www.facebook.com/UnityUIExtensions/) / [YouTube](https://www.youtube.com/channel/UCG3gZOkmL-2rmZat4ufv28Q)
### [Twitter - #unityuiextensions](https://twitter.com/search?q=%23unityuiextensions) / [Facebook](https://www.facebook.com/UnityUIExtensions/) / [YouTube](https://www.youtube.com/@UnityUIExtensions)
> ## Chat live with the Unity UI Extensions community on Gitter here:
> Ways to get in touch:
>
> ## [UI Extensions Live Chat](https://gitter.im/Unity-UI-Extensions/Lobby)
> - [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project
> - [GitHub Discussions](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions), if you have any questions, queries or suggestions
-----
## [What is this repository for?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/About)
## [What is this repository for?](https://unity-ui-extensions.github.io/About)
In this repository is a collection of extension scripts / effects and controls to enhance your Unity UI experience. These scripts have been gathered from many sources, combined and improved over time.
@ -28,19 +29,19 @@ In this repository is a collection of extension scripts / effects and controls t
You can either download / fork this project to access the scripts, or you can also download these pre-compiled Unity Assets, chock full of goodness for each release:
## [Download - 2019.6 (aka 2.5)](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
## [Download - 2019.6 (aka 2.5)](https://unity-ui-extensions.github.io/Downloads)
We have expanded where you can download the UnityPackage asset and widened the options to contribute to the project.
> I will still stress however, ***contribution is optional***. **The assets / code will always remain FREE**
| [![Download from Itch.IO](https://bytebucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/itchio.png)](https://unityuiextensions.itch.io/uiextensions2-0 "Download from Itch.IO") | [![Download from Itch.IO](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/unionassets.png)](https://unionassets.com/unity-ui-extensions "Download from Union Assets") | [![Download from Itch.IO](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/patreon.jpg)](https://www.patreon.com/UnityUIExtensions "Support Unity UI Extensions on Patreon & download")|
| [![Download from Itch.IO](https://unity-ui-extensions.github.io/SiteImages/itchio.png)](https://unityuiextensions.itch.io/uiextensions2-0 "Download from Itch.IO") | [![Download from Itch.IO](https://unity-ui-extensions.github.io/SiteImages/unionassets.png)](https://unionassets.com/unity-ui-extensions "Download from Union Assets") | [![Download from Itch.IO](https://unity-ui-extensions.github.io/SiteImages/patreon.jpg)](https://www.patreon.com/UnityUIExtensions "Support Unity UI Extensions on Patreon & download")|
| :--- | :--- | :--- |
| [Grab from Itchio](https://unityuiextensions.itch.io/uiextensions2-0) | [Obtain via Union Assets](https://unionassets.com/unity-ui-extensions) |[Support through Patreon](https://www.patreon.com/UnityUIExtensions) |
> Still available to download on the [BitBucket site](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/downloads) if you prefer
> Still available to download on the [GitHub site](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/releases) if you prefer
To view previous releases, visit the [release archive](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
To view previous releases, visit the [release archive](https://unity-ui-extensions.github.io/Downloads)
-----
@ -50,15 +51,15 @@ If you wish to further support the Unity UI Extensions project itself, then you
All funds go to support the project, no matter the amount. **Donations in code are also extremely welcome**
| | |
|---|---|
| [![Donate via PayPal](https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-150px.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=89L8T9N6BR7LJ "Donating via Paypal") | [![Buy us a Coffee](https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/5cbed8a4ae2b88347c06c923_BuyMeACoffee_blue-p-500.png)](https://ko-fi.com/uiextensions "Buy us a Coffee") |
|[![Donate via PayPal](https://www.paypalobjects.com/webstatic/mktg/Logo/pp-logo-150px.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=89L8T9N6BR7LJ "Donating via Paypal")|[![Buy us a Coffee](https://uploads-ssl.webflow.com/5c14e387dab576fe667689cf/5cbed8a4ae2b88347c06c923_BuyMeACoffee_blue-p-500.png)](https://ko-fi.com/uiextensions "Buy us a Coffee")|
|-|-|
|||
> (PayPal account not required and you can remain anonymous if you wish)
-----
## [Getting Started](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
## [Getting Started](https://unity-ui-extensions.github.io/GettingStarted)
To get started with the project, here's a little guide:
@ -66,58 +67,92 @@ To get started with the project, here's a little guide:
-----
## [Updates:](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ReleaseNotes/RELEASENOTES)
## [Updates:](https://unity-ui-extensions.github.io/ReleaseNotes/RELEASENOTES)
## Maintenance release 2019.6 - 2.5 - Bug squash
## Release 2.3 - Reanimation - 2022/02/07
Its been a while since the last update and although Unity keeps changing, thankfully the parts underneath do not. THanks to some awesome work by our contributors and the test teams, we made a run on some underlying bugs and issues. If you spot anything else, please log it on the BitBucket site for resolution.
It has been a tough time for all since the last update, but things have been moving steadily along. In the past few months there has been a concerted effort to revamp and update the project ready for Unity 2022, as well as migrating the source repository over to GitHub and refreshing all the things.
We hope the new release is better for everyone and we have paid close attention to the editor menus and places to find all the controls for this release.
Be sure to also check out the "Examples" option in the Package Manager window to import the samples to your project.
To get up to speed with the Unity UI Extensions, check out the [Getting Started](https://unity-ui-extensions.github.io/GettingStarted.html) Page.
> Be sure to logon to the new [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project, if you have any questions, queries or suggestions
> Ways to get in touch:
>
> - [Gitter Chat](https://gitter.im/Unity-UI-Extensions/Lobby) site for the UI Extensions project
> - [GitHub Discussions](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions), if you have any questions, queries or suggestions
>
> Much easier that posting a question / issue on YouTube, Twitter or Facebook :D
>
> ## [UIExtensions Gitter Channel](https://gitter.im/Unity-UI-Extensions/Lobby)
### New / updated features
## Breaking changes
- Updated UI Line connector to use relative position instead of anchored position to verify if the Lines need updating.
- Allow menu prefabs to not have to have canvas components. This allows you to use any type of prefab as a "menu". Adam Kapos mentions the concept on the Unite talk, https://youtu.be/wbmjturGbAQ?t=1654
- Updated segment line drawing for Line Lists. Seems Unity no longer needs UV's to be wrapped manually.
- Updated the AutoCompleteComboBox to display text as entered (instead of all lowercase)
- Updated the ComboBox to display text as entered (instead of all lowercase)
- Updated ComboBox Examples to include programmatic versions
- Further ComboBox improvements including:
* Upwards panel
* Start fixes
* Item Template resize
* Disabled sorting on combobox as it wasn't working
* Disabled Slider handle when not in use
* Updated Example
- Updated the new Input system switch and tested against 2021
For customers upgrading from earlier versions of Unity to Unity 2020, please be aware of the Breaking change related to Text Based components. You will need to manually replace any UI using the older ```Text``` component and replace them with ```TextMeshPro``` versions. This is unavoidable due to Unity deprecating the Text component.
### Examples / Examples / Examples
> New users to 2022 are unaffected as all the Editor commands have been updated to use the newer TextMeshPro versions.
Examples can be found either in the UPM package manager window or via the extra downloadable UnityAsset from the Bitbucket site - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads
For more details, see the [deprecation notice](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/discussions/428) on GitHub.
### Fixes
## Added
- Reordering issue resolved with ScrollRectOcclusion.
- Fixed Sorting at min and max positions for ScrollRect
- Updated ScrollToSelect script provided by zero3growlithe, tested and vastly reduces the previous jitter. Still present but barely noticeable now.
- Fixed Issue # 363 Update Combobox control that takes multiple items programmatically, to only allow distinct items
- Fixed the issues where dragging outside the range slider handle causes the range to update. - Resolves #369
- Resolves an issue with Unity putting the previous controls vertex array in an uninitialised control.
- Applied J.R. Mitchell's fix for the Accordion Controls/Accordion/AccordionElement.cs - resolves: #364
- Resolved issue where the Content Scroll snap issue with only 1 child. Resolves #362
- Updated the PaginationManager to override if the ScrollSnap is in motion.
- Added new FIFO based UI Line Render when dynamic line rendering is needed.
- Added ResetSelectableHighlight component.
- Added SetArc method to UICircle as requested.
- Added new UIHorizontalScroller based on UIVerticalScroller.
- Added OnHighlightChanged and OnPressChanged events for UI Button.
- Added error handling around setting Unity UI Components for Vertical/Horizontal ScrollSnaps.
- Added Editor Menu Option to create a Min/Max slider.
- Added the ability to set a specific item for combobox controls on start and not just the first.
- Added the ability to disable the combo boxes and make them read-only.
### Known issues
## Changed
No new issues in this release, but check the issues list for things we are currently working on:
- Refresh FancyScrollView with the latest fixes
- All Text based components updated to use TextMeshPro from Unity 2022 **Breaking Change**
* [UI Extensions Issue log](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues?status=new&status=open)
- Clean-up and reset pivots on scene start.
- Merged in feature/improved-ui-highlightable (pull request UILineRenderer - issues with specifying point locations at runtime #123).
- Merged in fix/ragesliderfix (pull request HorizontalScrollSnap Mask Area doesn't work when content created dynamically #125).
- Merged in fix/infinitescrollcontentsize (pull request Gradient initialization should be in Awake() #126).
- Merged in feature/controlTouchUp (pull request UILineRenderer mesh not updating in Editor scene view #127).
- Upgraded RangeSlider to work in both Horizontal and Vertical setups.
- Merged in RangeSlider-upgrade. (pull request Newtonsoft.Json.dll conflict #131)
- Updated UIVertical scroller to be 2022 compliant.
- Updated Curly UI to wait until end of the frame to recalculate positions.
- Updated Depth Texture sampler in UI Particles Shaders.
- Updated Points to always be an array of 1 when set to nothing for the Line Renderer.
- Updated Cooldown button to work with Keyboard input.
- Removed unneeded size calculation which caused some issues with mixed content.
- Resolved an issue whereby the last row in a flow layout group would not size correctly.
- Updated all components using "LayoutGroup" to override their OnDisable.
- Updated validation in the new MinMaxSlider.
- Updated Editor create options to add the correct Event System Input manager.
- Updated initialisation logic to not cause an endless loop in the TabNavigationHelper.
- Updated "Action" use to "UnityAction" to avoid Unity issues for DropDowns.
- Updated UIVerticalScroller for standards.
- Updated ReorderableList/ReorderableListElement to prevent creating a fake object for non-transferable items.
- Updated panel drawing for ComboBox controls and added DropdownOffset.
- Updated build issue with ReorderableListElement.
- Updated NonDrawingGraphic to require a CanvasRender, else it causes an error on run.
## Deprecated
- Marked ScrollPositionController as Obsolete, users should use the new Scoller.
- BestFitOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- NicerOutline - Deprecated in Unity 2020 onwards. (still available for earlier versions)
- Marked TileSizeFitter as obsolete as Unity has made this unworkable.
## Fixed
- Resolved issues with DisplayAbove and using a 0 ItemsToDisplay for ComboBox controls.
- Resolved startup issue that prevented the control from being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes.
- Patch fix for UILineRenderer.
- Resolves issue where the lower range value would become stuck when moving.
- Updated Infinite scroll to work with content of different sizes.
- Updated Dropdown list to NOT resize text Rect on draw.
- Revised the Curly UI fix as it was preventing the graphic from being updated in the scene view.
- Cleanup and ensuring the UIParticleSystem is disposed in onDestroy correctly.
- Clean up range slider unused variables.
* [UI Extensions Issue log](https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues)
## Upgrade Notes
@ -129,79 +164,88 @@ We recommend using the UPM delivery method. If you are using the Unity asset, th
For the full release history, follow the below link to the full release notes page.
### [Release Notes](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ReleaseNotes/RELEASENOTES)
### [Release Notes](https://unity-ui-extensions.github.io/ReleaseNotes/RELEASENOTES)
-----
## [Controls and extensions listed in this project](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls)
## [Controls and extensions listed in this project](https://unity-ui-extensions.github.io/Controls)
There are almost 70+ extension controls / effect and other utilities in the project which are listed on the following page:
> ## [Check out the control demos on our Tumblr page](https://www.tumblr.com/blog/unityuiextensions)
>
> | [![UI Line Renderer](https://bytebucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/LineRenderer.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Line Renderer") | [![UI Knob](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/UIKnob.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Knob") | [![ScrollSnap](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/SiteImages/ScrollSnap.gif)](https://www.tumblr.com/blog/unityuiextensions "Scroll Snap")|
> | [![UI Line Renderer](https://unity-ui-extensions.github.io/SiteImages/LineRenderer.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Line Renderer") | [![UI Knob](https://unity-ui-extensions.github.io/SiteImages/UIKnob.gif)](https://www.tumblr.com/blog/unityuiextensions "UI Knob") | [![ScrollSnap](https://unity-ui-extensions.github.io/SiteImages/ScrollSnap.gif)](https://www.tumblr.com/blog/unityuiextensions "Scroll Snap")|
> | :--- | :--- | :--- |
> | [UI Line Renderer](https://www.tumblr.com/blog/unityuiextensions) | [UI Knob](https://www.tumblr.com/blog/unityuiextensions) |[Scroll Snap](https://www.tumblr.com/blog/unityuiextensions) |
## [UI Extensions controls list](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls)
## [UI Extensions controls list](https://unity-ui-extensions.github.io/Controls)
[Controls](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-controls)|||||
------|------|------|------|------|
Accordion|ColorPicker|Selection Box|UI Flippable|ComboBox
AutoComplete ComboBox|DropDown List|BoundToolTip|UIWindowBase|UI Knob
TextPic|Input Focus|Box Slider|Cooldown Button|Segmented Control
Stepper|Range Slider|Radial Slider|MultiTouch Scroll Rect|
||||
[Controls](https://unity-ui-extensions.github.io/Controls.html#controls)
[Primitives](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-primitives)|||||
------|------|------|------|------|
UILineRenderer|UILineTextureRenderer|UICircle|DiamondGraph|UICornerCut
UIPolygon||||
||||
|Accordion|ColorPicker|Selection Box|UI Flippable|ComboBox|
|-|-|-|-|-|
|AutoComplete ComboBox|DropDown List|BoundToolTip|UIWindowBase|UI Knob|
|TextPic|Input Focus|Box Slider|Cooldown Button|Segmented Control|
|Stepper|Range Slider|Radial Slider|MultiTouch Scroll Rect|MinMax SLider|
[Layouts](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-layouts)|||||
------|------|------|------|------|
Horizontal Scroll Snap|Vertical Scroll Snap|Flow Layout Group|Radial Layout|Tile Size Fitter
Scroll Snap (alt implementation)|Reorderable List|UI Vertical Scroller|Curved Layout|Table Layout
FancyScrollView|Card UI|Scroll Position Controller||
||||
[Primitives](https://unity-ui-extensions.github.io/Controls.html#primitives)
[Effects](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-effect_components)|||||
------|------|------|------|------|
Best Fit Outline|Curved Text|Gradient|Gradient2|Letter Spacing
NicerOutline|RaycastMask|UIFlippable|UIImageCrop|SoftAlphaMask
CylinderText|UIParticleSystem|CurlyUI|Shine Effect|Shader Effects
||||
|UILineRenderer|UILineTextureRenderer|UICircle|DiamondGraph|UICornerCut|
|-|-|-|-|-|
|UIPolygon|UISquircle||||
[Additional Components](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Controls#markdown-header-additional_components)|||||
------|------|------|------|------|
ReturnKeyTrigger|TabNavigation|uGUITools|ScrollRectTweener|ScrollRectLinker
ScrollRectEx|UI_InfiniteScroll|UI_ScrollRectOcclusion|UIScrollToSelection|UISelectableExtension
switchToRectTransform|ScrollConflictManager|CLFZ2 (Encryption)|DragCorrector|PPIViewer
UI_TweenScale|UI_MagneticInfiniteScroll|UI_ScrollRectOcclusion|NonDrawingGraphic|
UILineConnector|UIHighlightable|Menu Manager|Pagination Manager|
||||
[Layouts](https://unity-ui-extensions.github.io/Controls.html#layouts)
|Horizontal Scroll Snap|Vertical Scroll Snap|Flow Layout Group|Radial Layout|Tile Size Fitter|
|-|-|-|-|-|
|Scroll Snap (alt implementation)|Reorderable List|UI Vertical Scroller|Curved Layout|Table Layout|
|FancyScrollView|Card UI|Scroll Position Controller (obsolete)|Content Scroll Snap Horizontal|Scroller|
|ResizePanel|RescalePanel|RescaleDragPanel|||
[Effects](https://unity-ui-extensions.github.io/Controls.html#effect-components)
|Best Fit Outline|Curved Text|Gradient|Gradient2|Letter Spacing|
|-|-|-|-|-|
|NicerOutline|RaycastMask|UIFlippable|UIImageCrop|SoftAlphaMask|
|CylinderText|UIParticleSystem|CurlyUI|Shine Effect|Shader Effects|
[Additional Components](https://unity-ui-extensions.github.io/Controls.html#additional-components)
|ReturnKeyTrigger|TabNavigation|uGUITools|ScrollRectTweener|ScrollRectLinker|
|-|-|-|-|-|
|ScrollRectEx|UI_InfiniteScroll|UI_ScrollRectOcclusion|UIScrollToSelection|UISelectableExtension|
|switchToRectTransform|ScrollConflictManager|CLFZ2 (Encryption)|DragCorrector|PPIViewer|
|UI_TweenScale|UI_MagneticInfiniteScroll|UI_ScrollRectOcclusion|NonDrawingGraphic|
|UILineConnector|
|UIHighlightable|Menu Manager|Pagination Manager|||
*More to come*
-----
## [How do I get set up?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/GettingStarted)
## [How do I get set up?](https://unity-ui-extensions.github.io/UPMInstallation.html)
As of Unity 2019, there are now two paths for getting access to the Unity UI Extensions project:
The recommended way to add the Unity UI Extensions project to your solution is to use the Unity package Manager. Simply use the Unity Package Manager to reference the project to install it
- Unity 2019 or higher
The recommended way to add the Unity UI Extensions project to your solution is to use the Unity package Manager. Simply use the [Unity Package Manager](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/UPMInstallation) to reference the project and install it.
New for 2020, we have added OpenUPM support and the package can be installed using the following [OpenUPM CLI](https://openupm.com/docs/) command:
Alternatively, you can also use the pre-compiled Unity packages if you wish, however, UPM offers full versioning support to allow you to switch versions as you wish.
```cli
`openupm add com.unity.uiextensions`
```
> For more details on using [OpenUPM CLI, check the docs here](https://github.com/openupm/openupm-cli#installation).
- Unity Package Manager - manual
Alternatively, you can also add the package manually through the Unity package manager using the scope ```com.unity.uiextensions```, see the [Unity Package Manager docs](https://learn.unity.com/tutorial/the-package-manager) for more information.
- Unity 2018 or lower
The pre-compiled Unity assets are the only solution for Unity 2018 or earlier due to the changes in the Unity UI framework in Unity made for 2019.
Either clone / download this repository to your machine and then copy the scripts in, or use the pre-packaged .UnityPackage for your version of Unity and import it as a custom package in to your project.
## [Contribution guidelines](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/ContributionGuidelines)
## [Contribution guidelines](https://unity-ui-extensions.github.io/ContributionGuidelines)
Got a script you want added? Then just fork the bitbucket repository and submit a PR. All contributions accepted (including fixes)
Got a script you want added? Then just fork the [GitHub repository](https://github.com/unity-UI-Extensions/com.unity.uiextensions) and submit a PR. All contributions accepted (including fixes)
Just ensure:
@ -209,21 +253,21 @@ Just ensure:
* The script uses the **Unity.UI.Extensions** namespace so they do not affect any other developments.
* (optional) Add Component and Editor options where possible. (editor options are in the Editor\UIExtensionsMenuOptions.cs file)
## [License](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/License)
## [License](https://raw.githubusercontent.com/Unity-UI-Extensions/com.unity.uiextensions/release/LICENSE.md)
All scripts conform to the BSD3 license and are free to use / distribute. See the [LICENSE](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/License) file for more information =
All scripts conform to the BSD3 license and are free to use / distribute. See the [LICENSE](https://raw.githubusercontent.com/Unity-UI-Extensions/com.unity.uiextensions/release/LICENSE.md) file for more information =
## [Like what you see?](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/FurtherInfo)
## [Like what you see?](https://unity-ui-extensions.github.io/FurtherInfo)
All these scripts were put together for my latest book Unity3D UI Essentials
Check out the [page on my blog](http://bit.ly/Unity3DUIEssentials) for more details and learn all about the inner workings of the new Unity UI System.
## [The downloads](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
## [The downloads](https://unity-ui-extensions.github.io/Downloads)
As this repo was created to support my new Unity UI Title ["Unity 3D UI Essentials"](http://bit.ly/Unity3DUIEssentials), in the downloads section you will find two custom assets (SpaceShip-DemoScene-Start.unitypackage and RollABallSample-Start.unitypackage). These are just here as starter scenes for doing UI tasks in the book.
I will add more sample scenes for the UI examples in this repository and detail them above over time.
## [Previous Releases](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads)
## [Previous Releases](https://unity-ui-extensions.github.io/Downloads)
Please see the [full downloads list](https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/wiki/Downloads) for all previous releases and their corresponding download links.
Please see the [full downloads list](https://unity-ui-extensions.github.io/Downloads) for all previous releases and their corresponding download links.

View File

@ -82,7 +82,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f IN) : SV_Target

View File

@ -82,7 +82,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -2,8 +2,7 @@ Shader "UI Extensions/Particles/Additive (Soft)" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -81,7 +80,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -3,8 +3,7 @@ Properties {
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -82,7 +81,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -2,8 +2,7 @@ Shader "UI Extensions/Particles/Blend" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -81,7 +80,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -2,8 +2,7 @@ Shader "UI Extensions/Particles/Multiply" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -80,7 +79,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -2,8 +2,7 @@ Shader "UI Extensions/Particles/Multiply (Double)" {
Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -81,7 +80,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f i) : SV_Target

View File

@ -3,8 +3,7 @@ Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
@ -82,7 +81,7 @@ Category {
return v;
}
sampler2D_float _CameraDepthTexture;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
float _InvFade;
fixed4 frag (v2f IN) : SV_Target

View File

@ -3,7 +3,7 @@ Properties {
_EmisColor ("Emissive Color", Color) = (.2,.2,.2,0)
_MainTex ("Particle Texture", 2D) = "white" {}
_StencilComp ("Stencil Comparison", Float) = 8
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255

View File

@ -5,83 +5,89 @@
namespace UnityEngine.UI.Extensions.ColorPicker
{
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
public class ColorLabel : MonoBehaviour
{
public ColorPickerControl picker;
public ColorValues type;
public string prefix = "R: ";
public float minValue = 0;
public float maxValue = 255;
public int precision = 0;
private Text label;
private void Awake()
{
label = GetComponent<Text>();
}
private void OnEnable()
{
if (Application.isPlaying && picker != null)
{
picker.onValueChanged.AddListener(ColorChanged);
picker.onHSVChanged.AddListener(HSVChanged);
}
}
private void OnDestroy()
{
if (picker != null)
{
picker.onValueChanged.RemoveListener(ColorChanged);
picker.onHSVChanged.RemoveListener(HSVChanged);
}
}
#if UNITY_EDITOR
private void OnValidate()
{
label = GetComponent<Text>();
UpdateValue();
}
#endif
private void ColorChanged(Color color)
public class ColorLabel : MonoBehaviour
{
UpdateValue();
}
public ColorPickerControl picker;
private void HSVChanged(float hue, float sateration, float value)
{
UpdateValue();
}
public ColorValues type;
private void UpdateValue()
{
if (picker == null)
public string prefix = "R: ";
public float minValue = 0;
public float maxValue = 255;
public int precision = 0;
#if UNITY_2022_1_OR_NEWER
private TMPro.TMP_Text label;
#else
private Text label;
#endif
private void Awake()
{
label.text = prefix + "-";
#if UNITY_2022_1_OR_NEWER
label = GetComponent<TMPro.TMP_Text>();
#else
label = GetComponent<Text>();
#endif
if (!label)
{
Debug.LogError($"{gameObject.name} does not have a Text component assigned for the {nameof(ColorLabel)}");
}
}
else
{
float value = minValue + (picker.GetValue(type) * (maxValue - minValue));
label.text = prefix + ConvertToDisplayString(value);
private void OnEnable()
{
if (Application.isPlaying && picker != null)
{
picker.onValueChanged.AddListener(ColorChanged);
picker.onHSVChanged.AddListener(HSVChanged);
}
}
private void OnDestroy()
{
if (picker != null)
{
picker.onValueChanged.RemoveListener(ColorChanged);
picker.onHSVChanged.RemoveListener(HSVChanged);
}
}
private void ColorChanged(Color color)
{
UpdateValue();
}
private void HSVChanged(float hue, float sateration, float value)
{
UpdateValue();
}
private void UpdateValue()
{
if (picker == null)
{
label.text = prefix + "-";
}
else
{
float value = minValue + (picker.GetValue(type) * (maxValue - minValue));
label.text = prefix + ConvertToDisplayString(value);
}
}
private string ConvertToDisplayString(float value)
{
if (precision > 0)
return value.ToString("f " + precision);
else
return Mathf.FloorToInt(value).ToString();
}
}
private string ConvertToDisplayString(float value)
{
if (precision > 0)
return value.ToString("f " + precision);
else
return Mathf.FloorToInt(value).ToString();
}
}
}

View File

@ -1,8 +1,11 @@
fileFormatVersion: 2
guid: 06851a815227e5044b0e3c1bf9b3a282
guid: dea5b3bc15f78d04d8dcae27500f784e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -59,7 +59,9 @@ namespace UnityEngine.UI.Extensions.ColorPicker
private void OnDestroy()
{
if (image.texture != null)
{
DestroyImmediate(image.texture);
}
}
#if UNITY_EDITOR

View File

@ -1,8 +1,11 @@
fileFormatVersion: 2
guid: ff46fbecea7739f4690e4285c88f53c5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
fileFormatVersion: 2
guid: 9d3cae3318559ae449731a7db00c9bdd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,12 +1,11 @@
fileFormatVersion: 2
guid: 3d95ce8fba3dbbf4eb14411412169b88
timeCreated: 1442747317
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 97950dcfb7ac51c4c95431d68ad7bea5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,8 +1,11 @@
fileFormatVersion: 2
guid: 4f3189246d7fc204faba7a1e9c08e0af
guid: 0e93d154602ed7e4787f2a7b9d3101b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,95 +7,95 @@ namespace UnityEngine.UI.Extensions.ColorPicker
{
[RequireComponent(typeof(InputField))]
public class HexColorField : MonoBehaviour
{
public ColorPickerControl ColorPicker;
public bool displayAlpha;
private InputField hexInputField;
private const string hexRegex = "^#?(?:[0-9a-fA-F]{3,4}){1,2}$";
private void Awake()
public class HexColorField : MonoBehaviour
{
hexInputField = GetComponent<InputField>();
public ColorPickerControl ColorPicker;
// Add listeners to keep text (and color) up to date
hexInputField.onEndEdit.AddListener(UpdateColor);
ColorPicker.onValueChanged.AddListener(UpdateHex);
}
public bool displayAlpha;
private void OnDestroy()
{
hexInputField.onValueChanged.RemoveListener(UpdateColor);
ColorPicker.onValueChanged.RemoveListener(UpdateHex);
}
private InputField hexInputField;
private void UpdateHex(Color newColor)
{
hexInputField.text = ColorToHex(newColor);
}
private const string hexRegex = "^#?(?:[0-9a-fA-F]{3,4}){1,2}$";
private void UpdateColor(string newHex)
{
Color32 color;
if (HexToColor(newHex, out color))
ColorPicker.CurrentColor = color;
else
Debug.Log("hex value is in the wrong format, valid formats are: #RGB, #RGBA, #RRGGBB and #RRGGBBAA (# is optional)");
}
private string ColorToHex(Color32 color)
{
if (displayAlpha)
return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.r, color.g, color.b, color.a);
else
return string.Format("#{0:X2}{1:X2}{2:X2}", color.r, color.g, color.b);
}
public static bool HexToColor(string hex, out Color32 color)
{
// Check if this is a valid hex string (# is optional)
if (System.Text.RegularExpressions.Regex.IsMatch(hex, hexRegex))
private void Awake()
{
int startIndex = hex.StartsWith("#") ? 1 : 0;
hexInputField = GetComponent<InputField>();
if (hex.Length == startIndex + 8) //#RRGGBBAA
{
color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 6, 2), NumberStyles.AllowHexSpecifier));
}
else if (hex.Length == startIndex + 6) //#RRGGBB
{
color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
255);
}
else if (hex.Length == startIndex + 4) //#RGBA
{
color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 3] + hex[startIndex + 3], NumberStyles.AllowHexSpecifier));
}
else //#RGB
{
color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
255);
}
return true;
// Add listeners to keep text (and color) up to date
hexInputField.onEndEdit.AddListener(UpdateColor);
ColorPicker.onValueChanged.AddListener(UpdateHex);
}
else
private void OnDestroy()
{
color = new Color32();
return false;
hexInputField.onValueChanged.RemoveListener(UpdateColor);
ColorPicker.onValueChanged.RemoveListener(UpdateHex);
}
private void UpdateHex(Color newColor)
{
hexInputField.text = ColorToHex(newColor);
}
private void UpdateColor(string newHex)
{
Color32 color;
if (HexToColor(newHex, out color))
ColorPicker.CurrentColor = color;
else
Debug.Log("hex value is in the wrong format, valid formats are: #RGB, #RGBA, #RRGGBB and #RRGGBBAA (# is optional)");
}
private string ColorToHex(Color32 color)
{
if (displayAlpha)
return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.r, color.g, color.b, color.a);
else
return string.Format("#{0:X2}{1:X2}{2:X2}", color.r, color.g, color.b);
}
public static bool HexToColor(string hex, out Color32 color)
{
// Check if this is a valid hex string (# is optional)
if (System.Text.RegularExpressions.Regex.IsMatch(hex, hexRegex))
{
int startIndex = hex.StartsWith("#") ? 1 : 0;
if (hex.Length == startIndex + 8) //#RRGGBBAA
{
color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 6, 2), NumberStyles.AllowHexSpecifier));
}
else if (hex.Length == startIndex + 6) //#RRGGBB
{
color = new Color32(byte.Parse(hex.Substring(startIndex, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 2, 2), NumberStyles.AllowHexSpecifier),
byte.Parse(hex.Substring(startIndex + 4, 2), NumberStyles.AllowHexSpecifier),
255);
}
else if (hex.Length == startIndex + 4) //#RGBA
{
color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 3] + hex[startIndex + 3], NumberStyles.AllowHexSpecifier));
}
else //#RGB
{
color = new Color32(byte.Parse("" + hex[startIndex] + hex[startIndex], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 1] + hex[startIndex + 1], NumberStyles.AllowHexSpecifier),
byte.Parse("" + hex[startIndex + 2] + hex[startIndex + 2], NumberStyles.AllowHexSpecifier),
255);
}
return true;
}
else
{
color = new Color32();
return false;
}
}
}
}
}

View File

@ -52,7 +52,9 @@ namespace UnityEngine.UI.Extensions.ColorPicker
private void OnDestroy()
{
if (image.texture != null)
{
DestroyImmediate(image.texture);
}
}
#if UNITY_EDITOR

View File

@ -1,6 +1,7 @@
///Credit perchik
///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
using System;
using System.Collections.Generic;
using System.Linq;
@ -13,10 +14,9 @@ namespace UnityEngine.UI.Extensions
}
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/AutoComplete ComboBox")]
[AddComponentMenu("UI/Extensions/ComboBox/AutoComplete ComboBox")]
public class AutoCompleteComboBox : MonoBehaviour
{
public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
/// <summary>
@ -24,17 +24,15 @@ namespace UnityEngine.UI.Extensions
/// <see cref="RemoveItem(string)"/> and <see cref="SetAvailableOptions(List{string})"/> methods as these also execute
/// the required methods to update to the current collection.
/// </summary>
[Header("AutoComplete Box Items")]
public List<string> AvailableOptions;
//private bool isInitialized = false;
private bool _isPanelActive = false;
private bool _hasDrawnOnce = false;
private InputField _mainInput;
private RectTransform _inputRT;
//private Button _arrow_Button;
private RectTransform _rectTransform;
private RectTransform _overlayRT;
@ -52,11 +50,16 @@ namespace UnityEngine.UI.Extensions
private List<string> _prunedPanelItems; //items that used to show in the drop-down
private Dictionary<string, GameObject> panelObjects;
private GameObject itemTemplate;
private bool _initialized;
public string Text { get; private set; }
[Header("Properties")]
[SerializeField]
private bool isActive = true;
[SerializeField]
private float _scrollBarWidth = 20.0f;
public float ScrollBarWidth
@ -69,9 +72,6 @@ namespace UnityEngine.UI.Extensions
}
}
// private int scrollOffset; //offset of the selected item
// private int _selectedIndex = 0;
[SerializeField]
private int _itemsToDisplay;
public int ItemsToDisplay
@ -84,71 +84,85 @@ namespace UnityEngine.UI.Extensions
}
}
public bool SelectFirstItemOnStart = false;
[SerializeField]
[SerializeField]
[Tooltip("Change input text color based on matching items")]
private bool _ChangeInputTextColorBasedOnMatchingItems = false;
public bool InputColorMatching{
get { return _ChangeInputTextColorBasedOnMatchingItems; }
set
{
_ChangeInputTextColorBasedOnMatchingItems = value;
if (_ChangeInputTextColorBasedOnMatchingItems) {
SetInputTextColor ();
}
}
}
public bool InputColorMatching
{
get { return _ChangeInputTextColorBasedOnMatchingItems; }
set
{
_ChangeInputTextColorBasedOnMatchingItems = value;
if (_ChangeInputTextColorBasedOnMatchingItems)
{
SetInputTextColor();
}
}
}
public float DropdownOffset = 10f;
//TODO design as foldout for Inspector
public Color ValidSelectionTextColor = Color.green;
public Color MatchingItemsRemainingTextColor = Color.black;
public Color NoItemsRemainingTextColor = Color.red;
public Color MatchingItemsRemainingTextColor = Color.black;
public Color NoItemsRemainingTextColor = Color.red;
public AutoCompleteSearchType autocompleteSearchType = AutoCompleteSearchType.Linq;
[SerializeField]
private float dropdownOffset;
[SerializeField]
private bool _displayPanelAbove = false;
public bool SelectFirstItemOnStart = false;
[SerializeField]
private int selectItemIndexOnStart = 0;
private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;
private bool _selectionIsValid = false;
[System.Serializable]
public class SelectionChangedEvent : UnityEngine.Events.UnityEvent<string, bool> {
}
[System.Serializable]
public class SelectionChangedEvent : Events.UnityEvent<string, bool> { }
[System.Serializable]
public class SelectionTextChangedEvent : UnityEngine.Events.UnityEvent<string> {
}
public class SelectionTextChangedEvent : Events.UnityEvent<string> { }
[System.Serializable]
public class SelectionValidityChangedEvent : UnityEngine.Events.UnityEvent<bool> {
}
[System.Serializable]
public class SelectionValidityChangedEvent : Events.UnityEvent<bool> { }
// fires when input text is changed;
public SelectionTextChangedEvent OnSelectionTextChanged;
// fires when an Item gets selected / deselected (including when items are added/removed once this is possible)
public SelectionValidityChangedEvent OnSelectionValidityChanged;
// fires in both cases
public SelectionChangedEvent OnSelectionChanged;
[System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { }
// fires when input text is changed;
[Header("Events")]
public SelectionTextChangedEvent OnSelectionTextChanged;
// fires when an Item gets selected / deselected (including when items are added/removed once this is possible)
public SelectionValidityChangedEvent OnSelectionValidityChanged;
// fires in both cases
public SelectionChangedEvent OnSelectionChanged;
// fires when item is changed;
public ControlDisabledEvent OnControlDisabled;
public void Awake()
{
Initialize();
}
public void Start()
{
if (SelectFirstItemOnStart && AvailableOptions.Count > 0) {
ToggleDropdownPanel (false);
OnItemClicked (AvailableOptions [0]);
}
public void Start()
{
if (shouldSelectItemOnStart && AvailableOptions.Count > 0)
{
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}
private bool Initialize()
{
if (_initialized) return true;
bool success = true;
try
{
@ -156,8 +170,6 @@ namespace UnityEngine.UI.Extensions
_inputRT = _rectTransform.Find("InputField").GetComponent<RectTransform>();
_mainInput = _inputRT.GetComponent<InputField>();
//_arrow_Button = _rectTransform.FindChild ("ArrowBtn").GetComponent<Button> ();
_overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
_overlayRT.gameObject.SetActive(false);
@ -167,7 +179,6 @@ namespace UnityEngine.UI.Extensions
_slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
_scrollHandleRT = _slidingAreaRT.Find("Handle").GetComponent<RectTransform>();
_itemsPanelRT = _scrollPanelRT.Find("Items").GetComponent<RectTransform>();
//itemPanelLayout = itemsPanelRT.gameObject.GetComponent<LayoutGroup>();
_canvas = GetComponentInParent<Canvas>();
_canvasRT = _canvas.GetComponent<RectTransform>();
@ -191,6 +202,8 @@ namespace UnityEngine.UI.Extensions
_prunedPanelItems = new List<string>();
_panelItems = new List<string>();
_initialized = true;
RebuildPanel();
return success;
}
@ -225,21 +238,25 @@ namespace UnityEngine.UI.Extensions
}
}
/// <summary>
/// Update the drop down selection to a specific index
/// </summary>
/// <param name="index"></param>
public void SelectItemIndex(int index)
{
ToggleDropdownPanel(false);
OnItemClicked(AvailableOptions[index]);
}
/// <summary>
/// Sets the given items as new content for the comboBox. Previous entries will be cleared.
/// </summary>
/// <param name="newOptions">New entries.</param>
public void SetAvailableOptions(List<string> newOptions)
{
var uniqueOptions = newOptions.Distinct().ToList();
if (newOptions.Count != uniqueOptions.Count)
{
Debug.LogWarning($"{nameof(AutoCompleteComboBox)}.{nameof(SetAvailableOptions)}: items may only exists once. {newOptions.Count - uniqueOptions.Count} duplicates.");
}
this.AvailableOptions.Clear();
this.AvailableOptions = uniqueOptions;
this.RebuildPanel();
var uniqueOptions = newOptions.Distinct().ToArray();
SetAvailableOptions(uniqueOptions);
}
/// <summary>
@ -255,18 +272,21 @@ namespace UnityEngine.UI.Extensions
}
this.AvailableOptions.Clear();
for (int i = 0; i < newOptions.Length; i++)
{
this.AvailableOptions.Add(newOptions[i]);
}
this.RebuildPanel();
this.RedrawPanel();
}
public void ResetItems()
{
AvailableOptions.Clear();
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -274,6 +294,11 @@ namespace UnityEngine.UI.Extensions
/// </summary>
private void RebuildPanel()
{
if (!_initialized)
{
Start();
}
if (_isPanelActive) ToggleDropdownPanel();
//panel starts with all options
@ -310,8 +335,11 @@ namespace UnityEngine.UI.Extensions
if (i < AvailableOptions.Count)
{
itemObjs[i].name = "Item " + i + " " + _panelItems[i];
#if UNITY_2022_1_OR_NEWER
itemObjs[i].transform.Find("Text").GetComponent<TMPro.TMP_Text>().text = AvailableOptions[i]; //set the text value
#else
itemObjs[i].transform.Find("Text").GetComponent<Text>().text = AvailableOptions[i]; //set the text value
#endif
Button itemBtn = itemObjs[i].GetComponent<Button>();
itemBtn.onClick.RemoveAllListeners();
string textOfItem = _panelItems[i]; //has to be copied for anonymous function or it gets garbage collected away
@ -322,7 +350,7 @@ namespace UnityEngine.UI.Extensions
panelObjects[_panelItems[i]] = itemObjs[i];
}
}
SetInputTextColor ();
SetInputTextColor();
}
/// <summary>
@ -337,63 +365,39 @@ namespace UnityEngine.UI.Extensions
ToggleDropdownPanel(true);
}
//private void UpdateSelected()
//{
// SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
// if (SelectedItem == null) return;
// bool hasImage = SelectedItem.Image != null;
// if (hasImage)
// {
// mainButton.img.sprite = SelectedItem.Image;
// mainButton.img.color = Color.white;
// //if (Interactable) mainButton.img.color = Color.white;
// //else mainButton.img.color = new Color(1, 1, 1, .5f);
// }
// else
// {
// mainButton.img.sprite = null;
// }
// mainButton.txt.text = SelectedItem.Caption;
// //update selected index color
// for (int i = 0; i < itemsPanelRT.childCount; i++)
// {
// panelItems[i].btnImg.color = (_selectedIndex == i) ? mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
// }
//}
private void RedrawPanel()
{
float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
_scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
float dropdownHeight = _itemsToDisplay > 0 ? _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) : _rectTransform.sizeDelta.y * _panelItems.Count;
dropdownHeight += dropdownOffset;
if (!_hasDrawnOnce || _rectTransform.sizeDelta != _inputRT.sizeDelta)
{
_hasDrawnOnce = true;
_inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
_inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
_scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
var itemsRemaining = _panelItems.Count - ItemsToDisplay;
itemsRemaining = itemsRemaining < 0 ? 0 : itemsRemaining;
_scrollPanelRT.SetParent(transform, true);
_scrollPanelRT.anchoredPosition = _displayPanelAbove ?
new Vector2(0, DropdownOffset + _rectTransform.sizeDelta.y * _panelItems.Count - 1) :
new Vector2(0, -_rectTransform.sizeDelta.y);
new Vector2(0, dropdownOffset + dropdownHeight) :
new Vector2(0, -(dropdownOffset + _rectTransform.sizeDelta.y));
//make the overlay fill the screen
_overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
_overlayRT.SetParent(_canvas.transform, false);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
_overlayRT.SetParent(transform, true);//reattach to this object
_scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
_overlayRT.SetParent(transform, true);
_scrollPanelRT.SetParent(_overlayRT, true);
}
if (_panelItems.Count < 1) return;
float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) + DropdownOffset;
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
@ -402,7 +406,7 @@ namespace UnityEngine.UI.Extensions
_scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, scrollbarWidth);
_scrollBarRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
if (scrollbarWidth == 0) _scrollHandleRT.gameObject.SetActive(false); else _scrollHandleRT.gameObject.SetActive(true);
if (scrollbarWidth == 0) _scrollHandleRT.gameObject.SetActive(false); else _scrollHandleRT.gameObject.SetActive(true);
_slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 0);
_slidingAreaRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight - _scrollBarRT.sizeDelta.x);
@ -413,7 +417,6 @@ namespace UnityEngine.UI.Extensions
Text = currText;
PruneItems(currText);
RedrawPanel();
//Debug.Log("value changed to: " + currText);
if (_panelItems.Count == 0)
{
@ -425,30 +428,36 @@ namespace UnityEngine.UI.Extensions
ToggleDropdownPanel(false);
}
bool validity_changed = (_panelItems.Contains (Text) != _selectionIsValid);
_selectionIsValid = _panelItems.Contains (Text);
OnSelectionChanged.Invoke (Text, _selectionIsValid);
OnSelectionTextChanged.Invoke (Text);
if(validity_changed){
OnSelectionValidityChanged.Invoke (_selectionIsValid);
}
bool validity_changed = (_panelItems.Contains(Text) != _selectionIsValid);
_selectionIsValid = _panelItems.Contains(Text);
OnSelectionChanged.Invoke(Text, _selectionIsValid);
OnSelectionTextChanged.Invoke(Text);
if (validity_changed)
{
OnSelectionValidityChanged.Invoke(_selectionIsValid);
}
SetInputTextColor ();
SetInputTextColor();
}
private void SetInputTextColor(){
if (InputColorMatching) {
if (_selectionIsValid) {
_mainInput.textComponent.color = ValidSelectionTextColor;
} else if (_panelItems.Count > 0) {
_mainInput.textComponent.color = MatchingItemsRemainingTextColor;
} else {
_mainInput.textComponent.color = NoItemsRemainingTextColor;
}
}
}
private void SetInputTextColor()
{
if (InputColorMatching)
{
if (_selectionIsValid)
{
_mainInput.textComponent.color = ValidSelectionTextColor;
}
else if (_panelItems.Count > 0)
{
_mainInput.textComponent.color = MatchingItemsRemainingTextColor;
}
else
{
_mainInput.textComponent.color = NoItemsRemainingTextColor;
}
}
}
/// <summary>
/// Toggle the drop down list
@ -456,6 +465,8 @@ namespace UnityEngine.UI.Extensions
/// <param name="directClick"> whether an item was directly clicked on</param>
public void ToggleDropdownPanel(bool directClick = false)
{
if (!isActive) return;
_isPanelActive = !_isPanelActive;
_overlayRT.gameObject.SetActive(_isPanelActive);
@ -469,6 +480,20 @@ namespace UnityEngine.UI.Extensions
}
}
/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status != isActive)
{
OnControlDisabled?.Invoke(status);
}
isActive = status;
}
private void PruneItems(string currText)
{
if (autocompleteSearchType == AutoCompleteSearchType.Linq)
@ -528,4 +553,4 @@ namespace UnityEngine.UI.Extensions
}
}
}
}
}

View File

@ -3,48 +3,61 @@
using System.Collections.Generic;
using System.Linq;
using static UnityEditor.Progress;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/ComboBox")]
[AddComponentMenu("UI/Extensions/ComboBox/ComboBox")]
public class ComboBox : MonoBehaviour
{
public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
public DropDownListItem SelectedItem { get; private set; }
[Header("Combo Box Items")]
public List<string> AvailableOptions;
[Header("Properties")]
[SerializeField]
private bool isActive = true;
[SerializeField]
private float _scrollBarWidth = 20.0f;
[SerializeField]
private int _itemsToDisplay;
//Sorting disabled as it causes issues.
//[SerializeField]
//private bool _sortItems = true;
[SerializeField]
private float dropdownOffset;
[SerializeField]
private bool _displayPanelAbove = false;
public bool SelectFirstItemOnStart = false;
[SerializeField]
private int selectItemIndexOnStart = 0;
private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;
[System.Serializable]
public class SelectionChangedEvent : UnityEngine.Events.UnityEvent<string>
{
}
public class SelectionChangedEvent : Events.UnityEvent<string> { }
[Header("Events")]
// fires when item is changed;
public SelectionChangedEvent OnSelectionChanged;
[System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { }
// fires when item is changed;
public ControlDisabledEvent OnControlDisabled;
//private bool isInitialized = false;
private bool _isPanelActive = false;
private bool _hasDrawnOnce = false;
private InputField _mainInput;
private RectTransform _inputRT;
private RectTransform _rectTransform;
private RectTransform _overlayRT;
private RectTransform _scrollPanelRT;
private RectTransform _scrollBarRT;
@ -53,14 +66,11 @@ namespace UnityEngine.UI.Extensions
private RectTransform _itemsPanelRT;
private Canvas _canvas;
private RectTransform _canvasRT;
private ScrollRect _scrollRect;
private List<string> _panelItems; //items that will get shown in the drop-down
private Dictionary<string, GameObject> panelObjects;
private GameObject itemTemplate;
private bool _initialized;
public string Text { get; private set; }
@ -74,9 +84,6 @@ namespace UnityEngine.UI.Extensions
}
}
// private int scrollOffset; //offset of the selected item
// private int _selectedIndex = 0;
public int ItemsToDisplay
{
get { return _itemsToDisplay; }
@ -94,11 +101,17 @@ namespace UnityEngine.UI.Extensions
public void Start()
{
if (shouldSelectItemOnStart && AvailableOptions.Count > 0)
{
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}
private bool Initialize()
{
if (_initialized) return true;
bool success = true;
try
{
@ -138,11 +151,22 @@ namespace UnityEngine.UI.Extensions
_panelItems = AvailableOptions.ToList();
_initialized = true;
RebuildPanel();
//RedrawPanel(); - causes an initialisation failure in U5
return success;
}
/// <summary>
/// Update the drop down selection to a specific index
/// </summary>
/// <param name="index"></param>
public void SelectItemIndex(int index)
{
ToggleDropdownPanel(false);
OnItemClicked(AvailableOptions[index]);
}
public void AddItem(string item)
{
AvailableOptions.Add(item);
@ -157,26 +181,34 @@ namespace UnityEngine.UI.Extensions
public void SetAvailableOptions(List<string> newOptions)
{
AvailableOptions.Clear();
AvailableOptions = newOptions;
RebuildPanel();
var uniqueOptions = newOptions.Distinct().ToArray();
SetAvailableOptions(uniqueOptions);
}
public void SetAvailableOptions(string[] newOptions)
{
AvailableOptions.Clear();
var uniqueOptions = newOptions.Distinct().ToList();
if (newOptions.Length != uniqueOptions.Count)
{
Debug.LogWarning($"{nameof(ComboBox)}.{nameof(SetAvailableOptions)}: items may only exists once. {newOptions.Length - uniqueOptions.Count} duplicates.");
}
this.AvailableOptions.Clear();
for (int i = 0; i < newOptions.Length; i++)
{
AvailableOptions.Add(newOptions[i]);
this.AvailableOptions.Add(newOptions[i]);
}
RebuildPanel();
this.RebuildPanel();
this.RedrawPanel();
}
public void ResetItems()
{
AvailableOptions.Clear();
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -184,13 +216,17 @@ namespace UnityEngine.UI.Extensions
/// </summary>
private void RebuildPanel()
{
if (!_initialized)
{
Start();
}
//panel starts with all options
_panelItems.Clear();
foreach (string option in AvailableOptions)
{
_panelItems.Add(option.ToLower());
}
//if(_sortItems) _panelItems.Sort();
List<GameObject> itemObjs = new List<GameObject>(panelObjects.Values);
panelObjects.Clear();
@ -211,8 +247,11 @@ namespace UnityEngine.UI.Extensions
if (i < AvailableOptions.Count)
{
itemObjs[i].name = "Item " + i + " " + _panelItems[i];
#if UNITY_2022_1_OR_NEWER
itemObjs[i].transform.Find("Text").GetComponent<TMPro.TMP_Text>().text = AvailableOptions[i]; //set the text value
#else
itemObjs[i].transform.Find("Text").GetComponent<Text>().text = AvailableOptions[i]; //set the text value
#endif
Button itemBtn = itemObjs[i].GetComponent<Button>();
itemBtn.onClick.RemoveAllListeners();
string textOfItem = _panelItems[i]; //has to be copied for anonymous function or it gets garbage collected away
@ -237,63 +276,39 @@ namespace UnityEngine.UI.Extensions
ToggleDropdownPanel(true);
}
//private void UpdateSelected()
//{
// SelectedItem = (_selectedIndex > -1 && _selectedIndex < Items.Count) ? Items[_selectedIndex] : null;
// if (SelectedItem == null) return;
// bool hasImage = SelectedItem.Image != null;
// if (hasImage)
// {
// mainButton.img.sprite = SelectedItem.Image;
// mainButton.img.color = Color.white;
// //if (Interactable) mainButton.img.color = Color.white;
// //else mainButton.img.color = new Color(1, 1, 1, .5f);
// }
// else
// {
// mainButton.img.sprite = null;
// }
// mainButton.txt.text = SelectedItem.Caption;
// //update selected index color
// for (int i = 0; i < itemsPanelRT.childCount; i++)
// {
// panelItems[i].btnImg.color = (_selectedIndex == i) ? mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
// }
//}
private void RedrawPanel()
{
float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
_scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
float dropdownHeight = _itemsToDisplay > 0 ? _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) : _rectTransform.sizeDelta.y * _panelItems.Count;
dropdownHeight += dropdownOffset;
if (!_hasDrawnOnce || _rectTransform.sizeDelta != _inputRT.sizeDelta)
{
_hasDrawnOnce = true;
_inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
_inputRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
_scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
var itemsRemaining = _panelItems.Count - ItemsToDisplay;
itemsRemaining = itemsRemaining < 0 ? 0 : itemsRemaining;
_scrollPanelRT.SetParent(transform, true);
_scrollPanelRT.anchoredPosition = _displayPanelAbove ?
new Vector2(0, _rectTransform.sizeDelta.y * ItemsToDisplay - 1) :
new Vector2(0, -_rectTransform.sizeDelta.y);
new Vector2(0, dropdownOffset + dropdownHeight) :
new Vector2(0, -(dropdownOffset + _rectTransform.sizeDelta.y));
//make the overlay fill the screen
_overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
_overlayRT.SetParent(_canvas.transform, false);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
_overlayRT.SetParent(transform, true);//reattach to this object
_scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
_overlayRT.SetParent(transform, true);
_scrollPanelRT.SetParent(_overlayRT, true);
}
if (_panelItems.Count < 1) return;
float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
@ -312,7 +327,6 @@ namespace UnityEngine.UI.Extensions
{
Text = currText;
RedrawPanel();
//Debug.Log("value changed to: " + currText);
if (_panelItems.Count == 0)
{
@ -332,6 +346,8 @@ namespace UnityEngine.UI.Extensions
/// <param name="directClick"> whether an item was directly clicked on</param>
public void ToggleDropdownPanel(bool directClick)
{
if (!isActive) return;
_isPanelActive = !_isPanelActive;
_overlayRT.gameObject.SetActive(_isPanelActive);
@ -344,5 +360,18 @@ namespace UnityEngine.UI.Extensions
// scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y);
}
}
/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status != isActive)
{
OnControlDisabled?.Invoke(status);
}
isActive = status;
}
}
}

View File

@ -1,7 +1,6 @@
///Credit perchik
///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
@ -10,13 +9,20 @@ namespace UnityEngine.UI.Extensions
/// Extension to the UI class which creates a dropdown list
/// </summary>
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Dropdown List")]
[AddComponentMenu("UI/Extensions/ComboBox/Dropdown List")]
public class DropDownList : MonoBehaviour
{
public Color disabledTextColor;
public DropDownListItem SelectedItem { get; private set; } //outside world gets to get this, not set it
public List<DropDownListItem> Items;
[Header("Dropdown List Items")]
public List<DropDownListItem> Items;
[Header("Properties")]
[SerializeField]
private bool isActive = true;
public bool OverrideHighlighted = true;
//private bool isInitialized = false;
@ -38,11 +44,12 @@ namespace UnityEngine.UI.Extensions
private ScrollRect _scrollRect;
private List<DropDownListButton> _panelItems;
private List<DropDownListButton> _panelItems = new List<DropDownListButton>();
private GameObject _itemTemplate;
private GameObject _itemTemplate;
private bool _initialized;
[SerializeField]
[SerializeField]
private float _scrollBarWidth = 20.0f;
public float ScrollBarWidth
{
@ -69,32 +76,45 @@ namespace UnityEngine.UI.Extensions
}
}
public bool SelectFirstItemOnStart = false;
[SerializeField]
private float dropdownOffset;
[SerializeField]
private bool _displayPanelAbove = false;
[SerializeField]
private bool _displayPanelAbove = false;
[SerializeField]
[Tooltip("Override the Text width for the values.")]
private bool _overrideTextWidth = true;
public bool SelectFirstItemOnStart = false;
[System.Serializable]
public class SelectionChangedEvent : UnityEngine.Events.UnityEvent<int> { }
// fires when item is changed;
public SelectionChangedEvent OnSelectionChanged;
[SerializeField]
private int selectItemIndexOnStart = 0;
private bool shouldSelectItemOnStart => SelectFirstItemOnStart || selectItemIndexOnStart > 0;
public void Start()
[System.Serializable]
public class SelectionChangedEvent : Events.UnityEvent<int> { }
// fires when item is changed;
[Header("Events")]
public SelectionChangedEvent OnSelectionChanged;
[System.Serializable]
public class ControlDisabledEvent : Events.UnityEvent<bool> { }
// fires when item is changed;
public ControlDisabledEvent OnControlDisabled;
public void Start()
{
Initialize();
if (shouldSelectItemOnStart && Items.Count > 0)
{
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}
private bool Initialize()
{
Initialize();
if (SelectFirstItemOnStart && Items.Count > 0) {
ToggleDropdownPanel (false);
OnItemClicked (0);
}
RedrawPanel();
}
if (_initialized) return true;
private bool Initialize()
{
bool success = true;
try
{
@ -103,8 +123,6 @@ namespace UnityEngine.UI.Extensions
_overlayRT = _rectTransform.Find("Overlay").GetComponent<RectTransform>();
_overlayRT.gameObject.SetActive(false);
_scrollPanelRT = _overlayRT.Find("ScrollPanel").GetComponent<RectTransform>();
_scrollBarRT = _scrollPanelRT.Find("Scrollbar").GetComponent<RectTransform>();
_slidingAreaRT = _scrollBarRT.Find("SlidingArea").GetComponent<RectTransform>();
@ -120,7 +138,6 @@ namespace UnityEngine.UI.Extensions
_scrollRect.movementType = ScrollRect.MovementType.Clamped;
_scrollRect.content = _itemsPanelRT;
_itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
_itemTemplate.SetActive(false);
}
@ -130,23 +147,32 @@ namespace UnityEngine.UI.Extensions
Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
success = false;
}
_initialized = true;
_panelItems = new List<DropDownListButton>();
RebuildPanel();
RebuildPanel();
RedrawPanel();
return success;
}
// currently just using items in the list instead of being able to add to it.
/// <summary>
/// Rebuilds the list from a new collection.
/// <summary>
/// Update the drop down selection to a specific index
/// </summary>
/// <remarks>
/// NOTE, this will clear all existing items
/// </remarks>
/// <param name="list"></param>
public void RefreshItems(params object[] list)
/// <param name="index"></param>
public void SelectItemIndex(int index)
{
ToggleDropdownPanel(false);
OnItemClicked(index);
}
// currently just using items in the list instead of being able to add to it.
/// <summary>
/// Rebuilds the list from a new collection.
/// </summary>
/// <remarks>
/// NOTE, this will clear all existing items
/// </remarks>
/// <param name="list"></param>
public void RefreshItems(params object[] list)
{
Items.Clear();
List<DropDownListItem> ddItems = new List<DropDownListItem>();
@ -171,72 +197,80 @@ namespace UnityEngine.UI.Extensions
}
Items.AddRange(ddItems);
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Adds an additional item to the drop down list (recommended)
/// </summary>
/// <param name="item">Item of type DropDownListItem</param>
public void AddItem(DropDownListItem item)
/// <summary>
/// Adds an additional item to the drop down list (recommended)
/// </summary>
/// <param name="item">Item of type DropDownListItem</param>
public void AddItem(DropDownListItem item)
{
Items.Add(item);
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Adds an additional drop down list item using a string name
/// </summary>
/// <param name="item">Item of type String</param>
public void AddItem(string item)
/// <summary>
/// Adds an additional drop down list item using a string name
/// </summary>
/// <param name="item">Item of type String</param>
public void AddItem(string item)
{
Items.Add(new DropDownListItem(caption: (string)item));
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Adds an additional drop down list item using a sprite image
/// </summary>
/// <param name="item">Item of type UI Sprite</param>
public void AddItem(Sprite item)
/// <summary>
/// Adds an additional drop down list item using a sprite image
/// </summary>
/// <param name="item">Item of type UI Sprite</param>
public void AddItem(Sprite item)
{
Items.Add(new DropDownListItem(image: (Sprite)item));
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Removes an item from the drop down list (recommended)
/// </summary>
/// <param name="item">Item of type DropDownListItem</param>
public void RemoveItem(DropDownListItem item)
/// <summary>
/// Removes an item from the drop down list (recommended)
/// </summary>
/// <param name="item">Item of type DropDownListItem</param>
public void RemoveItem(DropDownListItem item)
{
Items.Remove(item);
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Removes an item from the drop down list item using a string name
/// </summary>
/// <param name="item">Item of type String</param>
public void RemoveItem(string item)
/// <summary>
/// Removes an item from the drop down list item using a string name
/// </summary>
/// <param name="item">Item of type String</param>
public void RemoveItem(string item)
{
Items.Remove(new DropDownListItem(caption: (string)item));
RebuildPanel();
}
RedrawPanel();
}
/// <summary>
/// Removes an item from the drop down list item using a sprite image
/// </summary>
/// <param name="item">Item of type UI Sprite</param>
public void RemoveItem(Sprite item)
/// <summary>
/// Removes an item from the drop down list item using a sprite image
/// </summary>
/// <param name="item">Item of type UI Sprite</param>
public void RemoveItem(Sprite item)
{
Items.Remove(new DropDownListItem(image: (Sprite)item));
RebuildPanel();
}
RedrawPanel();
}
public void ResetItems()
public void ResetItems()
{
Items.Clear();
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -246,6 +280,11 @@ namespace UnityEngine.UI.Extensions
{
if (Items.Count == 0) return;
if (!_initialized)
{
Start();
}
int indx = _panelItems.Count;
while (_panelItems.Count < Items.Count)
{
@ -302,9 +341,6 @@ namespace UnityEngine.UI.Extensions
{
_mainButton.img.sprite = SelectedItem.Image;
_mainButton.img.color = Color.white;
//if (Interactable) mainButton.img.color = Color.white;
//else mainButton.img.color = new Color(1, 1, 1, .5f);
}
else
{
@ -316,7 +352,6 @@ namespace UnityEngine.UI.Extensions
//update selected index color
if (OverrideHighlighted)
{
for (int i = 0; i < _itemsPanelRT.childCount; i++)
{
_panelItems[i].btnImg.color = (_selectedIndex == i) ? _mainButton.btn.colors.highlightedColor : new Color(0, 0, 0, 0);
@ -324,40 +359,40 @@ namespace UnityEngine.UI.Extensions
}
}
private void RedrawPanel()
private void RedrawPanel()
{
float scrollbarWidth = Items.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
float scrollbarWidth = _panelItems.Count > ItemsToDisplay ? _scrollBarWidth : 0f;//hide the scrollbar if there's not enough items
_scrollBarRT.gameObject.SetActive(_panelItems.Count > ItemsToDisplay);
if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta)
float dropdownHeight = _itemsToDisplay > 0 ? _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, _panelItems.Count) : _rectTransform.sizeDelta.y * _panelItems.Count;
dropdownHeight += dropdownOffset;
if (!_hasDrawnOnce || _rectTransform.sizeDelta != _mainButton.rectTransform.sizeDelta)
{
_hasDrawnOnce = true;
_mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
_mainButton.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _rectTransform.sizeDelta.y);
if (_overrideTextWidth)
{
_mainButton.txt.rectTransform.offsetMax = new Vector2(4, 0);
}
_scrollPanelRT.SetParent(transform, true);//break the scroll panel from the overlay
_scrollPanelRT.anchoredPosition = _displayPanelAbove ?
new Vector2(0, _rectTransform.sizeDelta.y * ItemsToDisplay - 1) :
new Vector2(0, -_rectTransform.sizeDelta.y);
var itemsRemaining = _panelItems.Count - ItemsToDisplay;
itemsRemaining = itemsRemaining < 0 ? 0 : itemsRemaining;
//make the overlay fill the screen
_overlayRT.SetParent(_canvas.transform, false); //attach it to top level object
_scrollPanelRT.SetParent(transform, true);
_scrollPanelRT.anchoredPosition = _displayPanelAbove ?
new Vector2(0, dropdownOffset + dropdownHeight) :
new Vector2(0, -(dropdownOffset + _rectTransform.sizeDelta.y));
//make the overlay fill the screen
_overlayRT.SetParent(_canvas.transform, false);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _canvasRT.sizeDelta.x);
_overlayRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, _canvasRT.sizeDelta.y);
_overlayRT.SetParent(transform, true);//reattach to this object
_scrollPanelRT.SetParent(_overlayRT, true); //reattach the scrollpanel to the overlay
_overlayRT.SetParent(transform, true);
_scrollPanelRT.SetParent(_overlayRT, true);
}
if (Items.Count < 1) return;
if (_panelItems.Count < 1) return;
float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, Items.Count);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
_itemsPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _scrollPanelRT.sizeDelta.x - scrollbarWidth - 5);
@ -377,6 +412,8 @@ namespace UnityEngine.UI.Extensions
/// <param name="directClick"> whether an item was directly clicked on</param>
public void ToggleDropdownPanel(bool directClick)
{
if (!isActive) return;
_overlayRT.transform.localScale = new Vector3(1, 1, 1);
_scrollBarRT.transform.localScale = new Vector3(1, 1, 1);
_isPanelActive = !_isPanelActive;
@ -390,5 +427,18 @@ namespace UnityEngine.UI.Extensions
// scrollOffset = Mathf.RoundToInt(itemsPanelRT.anchoredPosition.y / _rectTransform.sizeDelta.y);
}
}
}
}
/// <summary>
/// Updates the control and sets its active status, determines whether the dropdown will open ot not
/// </summary>
/// <param name="status"></param>
public void SetActive(bool status)
{
if (status != isActive)
{
OnControlDisabled?.Invoke(status);
}
isActive = status;
}
}
}

View File

@ -8,7 +8,11 @@ namespace UnityEngine.UI.Extensions
{
public RectTransform rectTransform;
public Button btn;
#if UNITY_2022_1_OR_NEWER
public TMPro.TMP_Text txt;
#else
public Text txt;
#endif
public Image btnImg;
public Image img;
public GameObject gameobject;
@ -19,7 +23,11 @@ namespace UnityEngine.UI.Extensions
rectTransform = btnObj.GetComponent<RectTransform>();
btnImg = btnObj.GetComponent<Image>();
btn = btnObj.GetComponent<Button>();
#if UNITY_2022_1_OR_NEWER
txt = rectTransform.Find("Text").GetComponent<TMPro.TMP_Text>();
#else
txt = rectTransform.Find("Text").GetComponent<Text>();
#endif
img = rectTransform.Find("Image").GetComponent<Image>();
}
}

View File

@ -2,6 +2,7 @@
///Sourced from - http://forum.unity3d.com/threads/receive-onclick-event-and-pass-it-on-to-lower-ui-elements.293642/
using System;
using UnityEngine.Events;
namespace UnityEngine.UI.Extensions
{
@ -76,9 +77,9 @@ namespace UnityEngine.UI.Extensions
set { _id = value; }
}
public Action OnSelect = null; //action to be called when this item is selected
public UnityAction OnSelect = null; //action to be called when this item is selected
internal Action OnUpdate = null; //action to be called when something changes.
internal UnityAction OnUpdate = null; //action to be called when something changes.
/// <summary>
/// Constructor for Drop Down List panelItems
@ -87,8 +88,8 @@ namespace UnityEngine.UI.Extensions
/// <param name="val">ID of the item </param>
/// <param name="image"></param>
/// <param name="disabled">Should the item start disabled</param>
/// <param name="onSelect">Action to be called when this item is selected</param>
public DropDownListItem(string caption = "", string inId = "", Sprite image = null, bool disabled = false, Action onSelect = null)
/// <param name="onSelect">UnityAction to be called when this item is selected</param>
public DropDownListItem(string caption = "", string inId = "", Sprite image = null, bool disabled = false, UnityAction onSelect = null)
{
_caption = caption;
_image = image;

View File

@ -7,15 +7,14 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Cooldown Button")]
public class CooldownButton : MonoBehaviour, IPointerDownHandler
public class CooldownButton : MonoBehaviour, IPointerDownHandler, ISubmitHandler
{
#region Sub-Classes
[System.Serializable]
public class CooldownButtonEvent : UnityEvent<PointerEventData.InputButton> { }
public class CooldownButtonEvent : UnityEvent<GameObject> { }
#endregion
#region Private variables
[SerializeField]
private float cooldownTimeout;
[SerializeField]
@ -33,7 +32,7 @@ namespace UnityEngine.UI.Extensions
[SerializeField][ReadOnly]
private int cooldownPercentComplete;
PointerEventData buttonSource;
BaseEventData buttonSource;
#endregion
#region Public Properties
@ -116,7 +115,6 @@ namespace UnityEngine.UI.Extensions
#endregion
#region Public Methods
/// <summary>
/// Pause Cooldown without resetting values, allows Restarting of cooldown
/// </summary>
@ -144,9 +142,9 @@ namespace UnityEngine.UI.Extensions
/// </summary>
public void StartCooldown()
{
PointerEventData emptySource = new PointerEventData(EventSystem.current);
BaseEventData emptySource = new BaseEventData(EventSystem.current);
buttonSource = emptySource;
OnCooldownStart.Invoke(emptySource.button);
OnCooldownStart.Invoke(emptySource.selectedObject);
cooldownTimeRemaining = cooldownTimeout;
CooldownActive = cooldownInEffect = true;
}
@ -161,7 +159,7 @@ namespace UnityEngine.UI.Extensions
cooldownPercentRemaining = 0;
cooldownPercentComplete = 100;
cooldownActive = cooldownInEffect = false;
if (OnCoolDownFinish != null) OnCoolDownFinish.Invoke(buttonSource.button);
OnCoolDownFinish?.Invoke(buttonSource.selectedObject);
}
/// <summary>
@ -171,27 +169,38 @@ namespace UnityEngine.UI.Extensions
{
cooldownActive = cooldownInEffect = false;
}
#endregion
#region IPointerDownHandler
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
{
HandleButtonClick(eventData);
}
#endregion
#region ISubmitHandler
public void OnSubmit(BaseEventData eventData)
{
HandleButtonClick(eventData);
}
#endregion ISubmitHandler
#region Private Methods
public void HandleButtonClick(BaseEventData eventData)
{
buttonSource = eventData;
if (CooldownInEffect)
{
if (OnButtonClickDuringCooldown != null) OnButtonClickDuringCooldown.Invoke(eventData.button);
OnButtonClickDuringCooldown?.Invoke(buttonSource.selectedObject);
}
if (!CooldownInEffect)
{
if(OnCooldownStart != null) OnCooldownStart.Invoke(eventData.button);
OnCooldownStart?.Invoke(buttonSource.selectedObject);
cooldownTimeRemaining = cooldownTimeout;
cooldownActive = cooldownInEffect = true;
}
}
#endregion
#endregion Private Methods
}
}

View File

@ -1,7 +1,6 @@
/// Credit Erdener Gonenc - @PixelEnvision
/*USAGE: Simply use that instead of the regular ScrollRect */
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu ("UI/Extensions/MultiTouchScrollRect")]

View File

@ -6,7 +6,6 @@ using UnityEngine.Events;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform)), DisallowMultipleComponent]
[AddComponentMenu("UI/Extensions/Re-orderable list")]
public class ReorderableList : MonoBehaviour
@ -31,11 +30,11 @@ namespace UnityEngine.UI.Extensions
// This sets every item size (when being dragged over this list) to the current size of the first element of this list
[Tooltip("Should items being dragged over this list have their sizes equalized?")]
public bool EqualizeSizesOnDrag = false;
public bool EqualizeSizesOnDrag = false;
[Tooltip("Maximum number of items this container can hold")]
public int maxItems = int.MaxValue;
[Header("UI Re-orderable Events")]
public ReorderableListHandler OnElementDropped = new ReorderableListHandler();
public ReorderableListHandler OnElementGrabbed = new ReorderableListHandler();
@ -62,7 +61,7 @@ namespace UnityEngine.UI.Extensions
}
}
Canvas GetCanvas()
public Canvas GetCanvas()
{
Transform t = transform;
Canvas canvas = null;
@ -73,8 +72,7 @@ namespace UnityEngine.UI.Extensions
while (canvas == null && lvl < lvlLimit)
{
canvas = t.gameObject.GetComponent<Canvas>();
if (canvas == null)
if (!t.gameObject.TryGetComponent<Canvas>(out canvas))
{
t = t.parent;
}
@ -95,7 +93,6 @@ namespace UnityEngine.UI.Extensions
private void Start()
{
if (ContentLayout == null)
{
Debug.LogError("You need to have a child LayoutGroup content set for the list: " + name, gameObject);
@ -114,7 +111,6 @@ namespace UnityEngine.UI.Extensions
Refresh();
}
#region Nested type: ReorderableListEventStruct
[Serializable]
@ -136,13 +132,10 @@ namespace UnityEngine.UI.Extensions
#endregion
#region Nested type: ReorderableListHandler
[Serializable]
public class ReorderableListHandler : UnityEvent<ReorderableListEventStruct>
{
}
public class ReorderableListHandler : UnityEvent<ReorderableListEventStruct> { }
public void TestReOrderableListTarget(ReorderableListEventStruct item)
{
@ -152,4 +145,4 @@ namespace UnityEngine.UI.Extensions
#endregion
}
}
}

View File

@ -21,7 +21,6 @@ namespace UnityEngine.UI.Extensions
if(_rect)StartCoroutine(RefreshChildren());
}
public void OnTransformChildrenChanged()
{
if(this.isActiveAndEnabled)StartCoroutine(RefreshChildren());

View File

@ -5,7 +5,11 @@ namespace UnityEngine.UI.Extensions
{
public class ReorderableListDebug : MonoBehaviour
{
#if UNITY_2022_1_OR_NEWER
public TMPro.TMP_Text DebugLabel;
#else
public Text DebugLabel;
#endif
void Awake()
{

View File

@ -8,31 +8,29 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform), typeof(LayoutElement))]
public class ReorderableListElement : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
[Tooltip("Can this element be dragged?")]
[SerializeField]
private bool IsGrabbable = true;
private bool isGrabbable = true;
[Tooltip("Can this element be transfered to another list")]
[Tooltip("Can this element be dropped in another container?")]
[SerializeField]
private bool _isTransferable = true;
private bool isTransferable = true;
[Tooltip("Can this element be dropped in space?")]
[SerializeField]
private bool isDroppableInSpace = false;
public bool IsTransferable
{
get { return _isTransferable; }
get { return isTransferable; }
set
{
_canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
_canvasGroup.blocksRaycasts = value;
_isTransferable = value;
isTransferable = value;
}
}
@ -61,7 +59,6 @@ namespace UnityEngine.UI.Extensions
#region IBeginDragHandler Members
public void OnBeginDrag(PointerEventData eventData)
{
if (!_canvasGroup) { _canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>(); }
@ -71,7 +68,7 @@ namespace UnityEngine.UI.Extensions
return;
//Can't drag, return...
if (!_reorderableList.IsDraggable || !this.IsGrabbable)
if (!_reorderableList.IsDraggable || !this.isGrabbable)
{
_draggingObject = null;
return;
@ -142,12 +139,9 @@ namespace UnityEngine.UI.Extensions
_isDragging = true;
}
#endregion
#region IDragHandler Members
public void OnDrag(PointerEventData eventData)
{
if (!_isDragging)
@ -179,7 +173,6 @@ namespace UnityEngine.UI.Extensions
//If nothing found or the list is not dropable, put the fake element outside
if (_currentReorderableListRaycasted == null || _currentReorderableListRaycasted.IsDropable == false
|| (_oldReorderableListRaycasted != _reorderableList && !IsTransferable)
|| ((_fakeElement.parent == _currentReorderableListRaycasted.Content
? _currentReorderableListRaycasted.Content.childCount - 1
: _currentReorderableListRaycasted.Content.childCount) >= _currentReorderableListRaycasted.maxItems && !_currentReorderableListRaycasted.IsDisplacable)
@ -194,7 +187,7 @@ namespace UnityEngine.UI.Extensions
}
}
//Else find the best position on the list and put fake element on the right index
else
else if (_currentReorderableListRaycasted == _reorderableList || IsTransferable)
{
if (_currentReorderableListRaycasted.Content.childCount < _currentReorderableListRaycasted.maxItems && _fakeElement.parent != _currentReorderableListRaycasted.Content)
{
@ -245,12 +238,9 @@ namespace UnityEngine.UI.Extensions
}
}
#endregion
#region Displacement
private void displaceElement(int targetIndex, Transform displaced)
{
_displacedFromIndex = targetIndex;
@ -343,7 +333,6 @@ namespace UnityEngine.UI.Extensions
}
public void finishDisplacingElement()
{
if (_displacedObject.parent == null)
@ -355,12 +344,9 @@ namespace UnityEngine.UI.Extensions
_displacedObject = null;
_displacedObjectLE = null;
}
#endregion
#region IEndDragHandler Members
public void OnEndDrag(PointerEventData eventData)
{
_isDragging = false;
@ -473,11 +459,9 @@ namespace UnityEngine.UI.Extensions
}
_canvasGroup.blocksRaycasts = true;
}
#endregion
void CancelDrag()
private void CancelDrag()
{
_isDragging = false;
//If it's a clone, delete it
@ -556,4 +540,4 @@ namespace UnityEngine.UI.Extensions
_canvasGroup = gameObject.GetOrAddComponent<CanvasGroup>();
}
}
}
}

View File

@ -1,9 +1,7 @@
/// Credit David Gileadi
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/12
using System;
using System.Collections;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
@ -205,7 +203,11 @@ namespace UnityEngine.UI.Extensions
void ChangeTextColor(Color targetColor)
{
#if UNITY_2022_1_OR_NEWER
var text = GetComponentInChildren<TMPro.TMP_Text>();
#else
var text = GetComponentInChildren<Text>();
#endif
if (!text)
return;

View File

@ -40,13 +40,21 @@ namespace UnityEngine.UI.Extensions
//We want the test object to be either a UI element, a 2D element or a 3D element, so we'll get the appropriate components
SpriteRenderer spriteRenderer;
Image image;
#if UNITY_2022_1_OR_NEWER
TMPro.TMP_Text text;
#else
Text text;
#endif
void Start()
{
spriteRenderer = transform.GetComponent<SpriteRenderer>();
image = transform.GetComponent<Image>();
#if UNITY_2022_1_OR_NEWER
text = transform.GetComponent<TMPro.TMP_Text>();
#else
text = transform.GetComponent<Text>();
#endif
}
void Update()
@ -86,8 +94,6 @@ namespace UnityEngine.UI.Extensions
{
GetComponent<UnityEngine.Renderer>().material.color = color;
}
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d7bdc7e70331fe24aba2c9549f84c657
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,371 +1,371 @@
///Credit judah4
///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/BoxSlider")]
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
{
public enum Direction
{
LeftToRight,
RightToLeft,
BottomToTop,
TopToBottom,
}
[Serializable]
public class BoxSliderEvent : UnityEvent<float, float> { }
[SerializeField]
private RectTransform m_HandleRect;
public RectTransform HandleRect { get { return m_HandleRect; } set { if (SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
[Space(6)]
[SerializeField]
private float m_MinValue = 0;
public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_MaxValue = 1;
public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private bool m_WholeNumbers = false;
public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_ValueX = 1f;
public float ValueX
{
get
{
if (WholeNumbers)
return Mathf.Round(m_ValueX);
return m_ValueX;
}
set
{
SetX(value);
}
}
public float NormalizedValueX
{
get
{
if (Mathf.Approximately(MinValue, MaxValue))
return 0;
return Mathf.InverseLerp(MinValue, MaxValue, ValueX);
}
set
{
this.ValueX = Mathf.Lerp(MinValue, MaxValue, value);
}
}
[SerializeField]
private float m_ValueY = 1f;
public float ValueY
{
get
{
if (WholeNumbers)
return Mathf.Round(m_ValueY);
return m_ValueY;
}
set
{
SetY(value);
}
}
public float NormalizedValueY
{
get
{
if (Mathf.Approximately(MinValue, MaxValue))
return 0;
return Mathf.InverseLerp(MinValue, MaxValue, ValueY);
}
set
{
this.ValueY = Mathf.Lerp(MinValue, MaxValue, value);
}
}
[Space(6)]
// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
[SerializeField]
private BoxSliderEvent m_OnValueChanged = new BoxSliderEvent();
public BoxSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
// Private fields
private Transform m_HandleTransform;
private RectTransform m_HandleContainerRect;
// The offset from handle position to mouse down position
private Vector2 m_Offset = Vector2.zero;
private DrivenRectTransformTracker m_Tracker;
// Size of each step.
float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
protected BoxSlider()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
if (WholeNumbers)
{
m_MinValue = Mathf.Round(m_MinValue);
m_MaxValue = Mathf.Round(m_MaxValue);
}
UpdateCachedReferences();
SetX(m_ValueX, false);
SetY(m_ValueY, false);
// Update rects since other things might affect them even if value didn't change.
if(!Application.isPlaying) UpdateVisuals();
#if UNITY_2018_3_OR_NEWER
if (!Application.isPlaying)
#else
var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
#endif
{
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
}
}
#endif // if UNITY_EDITOR
public virtual void Rebuild(CanvasUpdate executing)
{
#if UNITY_EDITOR
if (executing == CanvasUpdate.Prelayout)
OnValueChanged.Invoke(ValueX, ValueY);
#endif
}
public void LayoutComplete()
{
}
public void GraphicUpdateComplete()
{
}
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
{
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
return false;
currentValue = newValue;
return true;
}
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
{
if (currentValue.Equals(newValue))
return false;
currentValue = newValue;
return true;
}
protected override void OnEnable()
{
base.OnEnable();
UpdateCachedReferences();
SetX(m_ValueX, false);
SetY(m_ValueY, false);
// Update rects since they need to be initialized correctly.
UpdateVisuals();
}
protected override void OnDisable()
{
m_Tracker.Clear();
base.OnDisable();
}
void UpdateCachedReferences()
{
if (m_HandleRect)
{
m_HandleTransform = m_HandleRect.transform;
if (m_HandleTransform.parent != null)
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
}
else
{
m_HandleContainerRect = null;
}
}
// Set the valueUpdate the visible Image.
void SetX(float input)
{
SetX(input, true);
}
void SetX(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, MinValue, MaxValue);
if (WholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_ValueX == newValue)
return;
m_ValueX = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(newValue, ValueY);
}
void SetY(float input)
{
SetY(input, true);
}
void SetY(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, MinValue, MaxValue);
if (WholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_ValueY == newValue)
return;
m_ValueY = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(ValueX, newValue);
}
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
UpdateVisuals();
}
enum Axis
{
Horizontal = 0,
Vertical = 1
}
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
private void UpdateVisuals()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
UpdateCachedReferences();
#endif
m_Tracker.Clear();
//to business!
if (m_HandleContainerRect != null)
{
m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[0] = anchorMax[0] = (NormalizedValueX);
anchorMin[1] = anchorMax[1] = (NormalizedValueY);
if (Application.isPlaying)
{
m_HandleRect.anchorMin = anchorMin;
m_HandleRect.anchorMax = anchorMax;
}
}
}
// Update the slider's position based on the mouse.
void UpdateDrag(PointerEventData eventData, Camera cam)
{
RectTransform clickRect = m_HandleContainerRect;
if (clickRect != null && clickRect.rect.size[0] > 0)
{
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
return;
localCursor -= clickRect.rect.position;
float val = Mathf.Clamp01((localCursor - m_Offset)[0] / clickRect.rect.size[0]);
NormalizedValueX = (val);
float valY = Mathf.Clamp01((localCursor - m_Offset)[1] / clickRect.rect.size[1]);
NormalizedValueY = (valY);
}
}
private bool CanDrag(PointerEventData eventData)
{
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
}
public override void OnPointerDown(PointerEventData eventData)
{
if (!CanDrag(eventData))
return;
base.OnPointerDown(eventData);
m_Offset = Vector2.zero;
if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
{
Vector2 localMousePos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
m_Offset = localMousePos;
m_Offset.y = -m_Offset.y;
}
else
{
// Outside the slider handle - jump to this point instead
UpdateDrag(eventData, eventData.pressEventCamera);
}
}
public virtual void OnDrag(PointerEventData eventData)
{
if (!CanDrag(eventData))
return;
UpdateDrag(eventData, eventData.pressEventCamera);
}
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
eventData.useDragThreshold = false;
}
}
}
///Credit judah4
///Sourced from - http://forum.unity3d.com/threads/color-picker.267043/
using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Sliders/BoxSlider")]
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
{
public enum Direction
{
LeftToRight,
RightToLeft,
BottomToTop,
TopToBottom,
}
[Serializable]
public class BoxSliderEvent : UnityEvent<float, float> { }
[SerializeField]
private RectTransform m_HandleRect;
public RectTransform HandleRect { get { return m_HandleRect; } set { if (SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
[Space(6)]
[SerializeField]
private float m_MinValue = 0;
public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_MaxValue = 1;
public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private bool m_WholeNumbers = false;
public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetX(m_ValueX); SetY(m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_ValueX = 1f;
public float ValueX
{
get
{
if (WholeNumbers)
return Mathf.Round(m_ValueX);
return m_ValueX;
}
set
{
SetX(value);
}
}
public float NormalizedValueX
{
get
{
if (Mathf.Approximately(MinValue, MaxValue))
return 0;
return Mathf.InverseLerp(MinValue, MaxValue, ValueX);
}
set
{
this.ValueX = Mathf.Lerp(MinValue, MaxValue, value);
}
}
[SerializeField]
private float m_ValueY = 1f;
public float ValueY
{
get
{
if (WholeNumbers)
return Mathf.Round(m_ValueY);
return m_ValueY;
}
set
{
SetY(value);
}
}
public float NormalizedValueY
{
get
{
if (Mathf.Approximately(MinValue, MaxValue))
return 0;
return Mathf.InverseLerp(MinValue, MaxValue, ValueY);
}
set
{
this.ValueY = Mathf.Lerp(MinValue, MaxValue, value);
}
}
[Space(6)]
// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
[SerializeField]
private BoxSliderEvent m_OnValueChanged = new BoxSliderEvent();
public BoxSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
// Private fields
private Transform m_HandleTransform;
private RectTransform m_HandleContainerRect;
// The offset from handle position to mouse down position
private Vector2 m_Offset = Vector2.zero;
private DrivenRectTransformTracker m_Tracker;
// Size of each step.
float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
protected BoxSlider()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
if (WholeNumbers)
{
m_MinValue = Mathf.Round(m_MinValue);
m_MaxValue = Mathf.Round(m_MaxValue);
}
UpdateCachedReferences();
SetX(m_ValueX, false);
SetY(m_ValueY, false);
// Update rects since other things might affect them even if value didn't change.
if(!Application.isPlaying) UpdateVisuals();
#if UNITY_2018_3_OR_NEWER
if (!Application.isPlaying)
#else
var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
#endif
{
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
}
}
#endif // if UNITY_EDITOR
public virtual void Rebuild(CanvasUpdate executing)
{
#if UNITY_EDITOR
if (executing == CanvasUpdate.Prelayout)
OnValueChanged.Invoke(ValueX, ValueY);
#endif
}
public void LayoutComplete()
{
}
public void GraphicUpdateComplete()
{
}
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
{
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
return false;
currentValue = newValue;
return true;
}
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
{
if (currentValue.Equals(newValue))
return false;
currentValue = newValue;
return true;
}
protected override void OnEnable()
{
base.OnEnable();
UpdateCachedReferences();
SetX(m_ValueX, false);
SetY(m_ValueY, false);
// Update rects since they need to be initialized correctly.
UpdateVisuals();
}
protected override void OnDisable()
{
m_Tracker.Clear();
base.OnDisable();
}
void UpdateCachedReferences()
{
if (m_HandleRect)
{
m_HandleTransform = m_HandleRect.transform;
if (m_HandleTransform.parent != null)
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
}
else
{
m_HandleContainerRect = null;
}
}
// Set the valueUpdate the visible Image.
void SetX(float input)
{
SetX(input, true);
}
void SetX(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, MinValue, MaxValue);
if (WholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_ValueX == newValue)
return;
m_ValueX = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(newValue, ValueY);
}
void SetY(float input)
{
SetY(input, true);
}
void SetY(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, MinValue, MaxValue);
if (WholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_ValueY == newValue)
return;
m_ValueY = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(ValueX, newValue);
}
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
UpdateVisuals();
}
enum Axis
{
Horizontal = 0,
Vertical = 1
}
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
private void UpdateVisuals()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
UpdateCachedReferences();
#endif
m_Tracker.Clear();
//to business!
if (m_HandleContainerRect != null)
{
m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[0] = anchorMax[0] = (NormalizedValueX);
anchorMin[1] = anchorMax[1] = (NormalizedValueY);
if (Application.isPlaying)
{
m_HandleRect.anchorMin = anchorMin;
m_HandleRect.anchorMax = anchorMax;
}
}
}
// Update the slider's position based on the mouse.
void UpdateDrag(PointerEventData eventData, Camera cam)
{
RectTransform clickRect = m_HandleContainerRect;
if (clickRect != null && clickRect.rect.size[0] > 0)
{
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
return;
localCursor -= clickRect.rect.position;
float val = Mathf.Clamp01((localCursor - m_Offset)[0] / clickRect.rect.size[0]);
NormalizedValueX = (val);
float valY = Mathf.Clamp01((localCursor - m_Offset)[1] / clickRect.rect.size[1]);
NormalizedValueY = (valY);
}
}
private bool CanDrag(PointerEventData eventData)
{
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
}
public override void OnPointerDown(PointerEventData eventData)
{
if (!CanDrag(eventData))
return;
base.OnPointerDown(eventData);
m_Offset = Vector2.zero;
if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
{
Vector2 localMousePos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
m_Offset = localMousePos;
m_Offset.y = -m_Offset.y;
}
else
{
// Outside the slider handle - jump to this point instead
UpdateDrag(eventData, eventData.pressEventCamera);
}
}
public virtual void OnDrag(PointerEventData eventData)
{
if (!CanDrag(eventData))
return;
UpdateDrag(eventData, eventData.pressEventCamera);
}
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
eventData.useDragThreshold = false;
}
}
}

View File

@ -0,0 +1,347 @@
///Credit brogan89
///Sourced from - https://github.com/brogan89/MinMaxSlider
using System;
using TMPro;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Sliders/MinMax Slider")]
public class MinMaxSlider : Selectable, IBeginDragHandler, IDragHandler, IEndDragHandler
{
private enum DragState
{
Both,
Min,
Max
}
[Header("UI Controls")]
[SerializeField] private Camera customCamera = null;
[SerializeField] private RectTransform sliderBounds = null;
[SerializeField] private RectTransform minHandle = null;
[SerializeField] private RectTransform maxHandle = null;
[SerializeField] private RectTransform middleGraphic = null;
// text components (optional)
[Header("Display Text (Optional)")]
[SerializeField] private TextMeshProUGUI minText = null;
[SerializeField] private TextMeshProUGUI maxText = null;
[SerializeField] private string textFormat = "0";
// values
[Header("Limits")]
[SerializeField] private float minLimit = 0;
[SerializeField] private float maxLimit = 100;
[Header("Values")]
public bool wholeNumbers;
[SerializeField] private float minValue = 25;
[SerializeField] private float maxValue = 75;
public MinMaxValues Values => new MinMaxValues(minValue, maxValue, minLimit, maxLimit);
public RectTransform SliderBounds { get => sliderBounds; set => sliderBounds = value; }
public RectTransform MinHandle { get => minHandle; set => minHandle = value; }
public RectTransform MaxHandle { get => maxHandle; set => maxHandle = value; }
public RectTransform MiddleGraphic { get => middleGraphic; set => middleGraphic = value; }
public TextMeshProUGUI MinText { get => minText; set => minText = value; }
public TextMeshProUGUI MaxText { get => maxText; set => maxText = value; }
/// <summary>
/// Event invoked when either slider value has changed
/// <para></para>
/// T0 = min, T1 = max
/// </summary>
[Serializable]
public class SliderEvent : UnityEvent<float, float> { }
public SliderEvent onValueChanged = new SliderEvent();
private Vector2 dragStartPosition;
private float dragStartMinValue01;
private float dragStartMaxValue01;
private DragState dragState;
private bool passDragEvents; // this allows drag events to be passed through to scrollers
private Camera mainCamera;
private Canvas parentCanvas;
private bool isOverlayCanvas;
protected override void Start()
{
base.Start();
if (!sliderBounds)
{
sliderBounds = transform as RectTransform;
}
parentCanvas = GetComponentInParent<Canvas>();
isOverlayCanvas = parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
mainCamera = customCamera != null ? customCamera : Camera.main;
}
public void SetLimits(float minLimit, float maxLimit)
{
this.minLimit = wholeNumbers ? Mathf.RoundToInt(minLimit) : minLimit;
this.maxLimit = wholeNumbers ? Mathf.RoundToInt(maxLimit) : maxLimit;
}
public void SetValues(MinMaxValues values, bool notify = true)
{
SetValues(values.minValue, values.maxValue, values.minLimit, values.maxLimit, notify);
}
public void SetValues(float minValue, float maxValue, bool notify = true)
{
SetValues(minValue, maxValue, minLimit, maxLimit, notify);
}
public void SetValues(float minValue, float maxValue, float minLimit, float maxLimit, bool notify = true)
{
this.minValue = wholeNumbers ? Mathf.RoundToInt(minValue) : minValue;
this.maxValue = wholeNumbers ? Mathf.RoundToInt(maxValue) : maxValue;
SetLimits(minLimit, maxLimit);
RefreshSliders();
UpdateText();
UpdateMiddleGraphic();
if (notify)
{
// event
onValueChanged.Invoke(this.minValue, this.maxValue);
}
}
private void RefreshSliders()
{
SetSliderAnchors();
float clampedMin = Mathf.Clamp(minValue, minLimit, maxLimit);
SetMinHandleValue01(minHandle, GetPercentage(minLimit, maxLimit, clampedMin));
float clampedMax = Mathf.Clamp(maxValue, minLimit, maxLimit);
SetMaxHandleValue01(maxHandle, GetPercentage(minLimit, maxLimit, clampedMax));
}
private void SetSliderAnchors()
{
minHandle.anchorMin = new Vector2(0, 0.5f);
minHandle.anchorMax = new Vector2(0, 0.5f);
minHandle.pivot = new Vector2(0.5f, 0.5f);
maxHandle.anchorMin = new Vector2(1, 0.5f);
maxHandle.anchorMax = new Vector2(1, 0.5f);
maxHandle.pivot = new Vector2(0.5f, 0.5f);
}
private void UpdateText()
{
if (minText)
{
minText.SetText(minValue.ToString(textFormat));
}
if (maxText)
{
maxText.SetText(maxValue.ToString(textFormat));
}
}
private void UpdateMiddleGraphic()
{
if (!middleGraphic) return;
middleGraphic.anchorMin = Vector2.zero;
middleGraphic.anchorMax = Vector2.one;
middleGraphic.offsetMin = new Vector2(minHandle.anchoredPosition.x, 0);
middleGraphic.offsetMax = new Vector2(maxHandle.anchoredPosition.x, 0);
}
#region IDragHandler
public void OnBeginDrag(PointerEventData eventData)
{
passDragEvents = Math.Abs(eventData.delta.x) < Math.Abs(eventData.delta.y);
if (passDragEvents)
{
PassDragEvents<IBeginDragHandler>(x => x.OnBeginDrag(eventData));
}
else
{
Camera uiCamera = isOverlayCanvas ? null : mainCamera;
RectTransformUtility.ScreenPointToLocalPointInRectangle(sliderBounds, eventData.position, uiCamera, out dragStartPosition);
float dragStartValue = GetValueOfPointInSliderBounds01(dragStartPosition);
dragStartMinValue01 = GetMinHandleValue01(minHandle);
dragStartMaxValue01 = GetMaxHandleValue01(maxHandle);
// set drag state
if (dragStartValue < dragStartMinValue01 || RectTransformUtility.RectangleContainsScreenPoint(minHandle, eventData.position, uiCamera))
{
dragState = DragState.Min;
minHandle.SetAsLastSibling();
}
else if (dragStartValue > dragStartMaxValue01 || RectTransformUtility.RectangleContainsScreenPoint(maxHandle, eventData.position, uiCamera))
{
dragState = DragState.Max;
maxHandle.SetAsLastSibling();
}
else
{
dragState = DragState.Both;
}
}
}
public void OnDrag(PointerEventData eventData)
{
if (passDragEvents)
{
PassDragEvents<IDragHandler>(x => x.OnDrag(eventData));
}
else if (minHandle && maxHandle)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(sliderBounds, eventData.position, isOverlayCanvas ? null : mainCamera, out Vector2 clickPosition);
SetSliderAnchors();
if (dragState == DragState.Min || dragState == DragState.Max)
{
float dragPosition01 = GetValueOfPointInSliderBounds01(clickPosition);
float minHandleValue = GetMinHandleValue01(minHandle);
float maxHandleValue = GetMaxHandleValue01(maxHandle);
if (dragState == DragState.Min)
SetMinHandleValue01(minHandle, Mathf.Clamp(dragPosition01, 0, maxHandleValue));
else if (dragState == DragState.Max)
SetMaxHandleValue01(maxHandle, Mathf.Clamp(dragPosition01, minHandleValue, 1));
}
else
{
float distancePercent = (clickPosition.x - dragStartPosition.x) / sliderBounds.rect.width;
SetMinHandleValue01(minHandle, dragStartMinValue01 + distancePercent);
SetMaxHandleValue01(maxHandle, dragStartMaxValue01 + distancePercent);
}
// set values
float min = Mathf.Lerp(minLimit, maxLimit, GetMinHandleValue01(minHandle));
float max = Mathf.Lerp(minLimit, maxLimit, GetMaxHandleValue01(maxHandle));
SetValues(min, max);
UpdateText();
UpdateMiddleGraphic();
}
}
public void OnEndDrag(PointerEventData eventData)
{
if (passDragEvents)
{
PassDragEvents<IEndDragHandler>(x => x.OnEndDrag(eventData));
}
else
{
float minHandleValue = GetMinHandleValue01(minHandle);
float maxHandleValue = GetMaxHandleValue01(maxHandle);
// this safe guards a possible situation where the slides can get stuck
if (Math.Abs(minHandleValue) < MinMaxValues.FLOAT_TOL && Math.Abs(maxHandleValue) < MinMaxValues.FLOAT_TOL)
{
maxHandle.SetAsLastSibling();
}
else if (Math.Abs(minHandleValue - 1) < MinMaxValues.FLOAT_TOL && Math.Abs(maxHandleValue - 1) < MinMaxValues.FLOAT_TOL)
{
minHandle.SetAsLastSibling();
}
}
}
#endregion IDragHandler
private void PassDragEvents<T>(Action<T> callback) where T : IEventSystemHandler
{
Transform parent = transform.parent;
while (parent != null)
{
foreach (var component in parent.GetComponents<Component>())
{
if (!(component is T)) continue;
callback.Invoke((T)(IEventSystemHandler)component);
return;
}
parent = parent.parent;
}
}
/// <summary>
/// Sets position of max handle RectTransform
/// </summary>
/// <param name="handle"></param>
/// <param name="value01">Normalized handle position</param>
private void SetMaxHandleValue01(RectTransform handle, float value01)
{
handle.anchoredPosition = new Vector2(value01 * sliderBounds.rect.width - sliderBounds.rect.width + sliderBounds.offsetMax.x, handle.anchoredPosition.y);
}
/// <summary>
/// Sets position of min handle RectTransform
/// </summary>
/// <param name="handle"></param>
/// <param name="value01">Normalized handle position</param>
private void SetMinHandleValue01(RectTransform handle, float value01)
{
handle.anchoredPosition = new Vector2(value01 * sliderBounds.rect.width + sliderBounds.offsetMin.x, handle.anchoredPosition.y);
}
/// <summary>
/// Returns normalized position of max handle RectTransform
/// </summary>
/// <param name="handle"></param>
/// <returns>Normalized position of max handle RectTransform</returns>
private float GetMaxHandleValue01(RectTransform handle)
{
return 1 + (handle.anchoredPosition.x - sliderBounds.offsetMax.x) / sliderBounds.rect.width;
}
/// <summary>
/// Returns normalized position of min handle RectTransform
/// </summary>
/// <param name="handle"></param>
/// <returns>Normalized position of min handle RectTransform</returns>
private float GetMinHandleValue01(RectTransform handle)
{
return (handle.anchoredPosition.x - sliderBounds.offsetMin.x) / sliderBounds.rect.width;
}
/// <summary>
/// Returns normalized position of a point in a slider bounds rectangle
/// </summary>
/// <param name="position"></param>
/// <returns>Normalized position of a point in a slider bounds rectangle</returns>
private float GetValueOfPointInSliderBounds01(Vector2 position)
{
var width = sliderBounds.rect.width;
return Mathf.Clamp((position.x + width / 2) / width, 0, 1);
}
/// <summary>
/// Returns percentage of input based on min and max values
/// </summary>
/// <param name="min"></param>
/// <param name="max"></param>
/// <param name="input"></param>
/// <returns></returns>
private static float GetPercentage(float min, float max, float input)
{
return (input - min) / (max - min);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b9f9954231c8bab419504a7ac5ff133e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -8,8 +8,8 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Radial Slider")]
[RequireComponent(typeof(Image))]
[AddComponentMenu("UI/Extensions/Sliders/Radial Slider")]
public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
private bool isPointerDown, isPointerReleased, lerpInProgress;

View File

@ -9,9 +9,9 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Range Slider", 34)]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Sliders/Range Slider", 34)]
public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
{
public enum Direction

View File

@ -9,9 +9,8 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
// Stepper control
[ExecuteInEditMode]
[AddComponentMenu("UI/Extensions/Stepper")]
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Sliders/Stepper")]
public class Stepper : UIBehaviour
{
private Selectable[] _sides;
@ -90,6 +89,28 @@ namespace UnityEngine.UI.Extensions
protected Stepper()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
RecreateSprites(sides);
if (separator)
LayoutSides();
if (!wrap)
{
DisableAtExtremes(sides);
}
}
#endif
protected override void Start()
{
if (isActiveAndEnabled)
StartCoroutine(DelayedInit());
}
protected override void OnEnable()
{
StartCoroutine(DelayedInit());

View File

@ -16,7 +16,12 @@ namespace UnityEngine.UI.Extensions {
[AddComponentMenu("UI/Extensions/TextPic")]
[ExecuteInEditMode] // Needed for culling images that are not used //
public class TextPic : Text, IPointerClickHandler, IPointerExitHandler, IPointerEnterHandler, ISelectHandler {
#if UNITY_2022_1_OR_NEWER
public class TextPic : TMPro.TMP_Text, IPointerClickHandler, IPointerExitHandler, IPointerEnterHandler, ISelectHandler
#else
public class TextPic : Text, IPointerClickHandler, IPointerExitHandler, IPointerEnterHandler, ISelectHandler
#endif
{
// Icon entry to replace text with
[Serializable]
public struct IconName {
@ -465,14 +470,21 @@ namespace UnityEngine.UI.Extensions {
/// UNITY METHODS ///
protected override void OnPopulateMesh(VertexHelper toFill) {
#if UNITY_2022_1_OR_NEWER
originalText = text;
text = GetOutputText();
base.OnPopulateMesh(toFill);
text = originalText;
#else
originalText = m_Text;
m_Text = GetOutputText();
base.OnPopulateMesh(toFill);
m_DisableFontTextureRebuiltCallback = true;
m_DisableFontTextureRebuiltCallback = true;
m_Text = originalText;
#endif
positions.Clear();
@ -539,8 +551,10 @@ namespace UnityEngine.UI.Extensions {
// Update the quad images
updateQuad = true;
#if !UNITY_2022_1_OR_NEWER
m_DisableFontTextureRebuiltCallback = false;
}
#endif
}
/// <summary>
/// Click event is detected whether to click a hyperlink text
@ -641,7 +655,7 @@ namespace UnityEngine.UI.Extensions {
#endif
protected override void OnEnable() {
#if UNITY_2019_1_OR_NEWER
#if UNITY_2019_1_OR_NEWER
// Here is the hack to see if Unity is using the new rendering system for text
usesNewRendering = false;
@ -660,13 +674,14 @@ namespace UnityEngine.UI.Extensions {
else {
usesNewRendering = true;
}
#endif
#endif
base.OnEnable();
#if !UNITY_2022_1_OR_NEWER
supportRichText = true;
alignByGeometry = true;
#endif
// Enable images on TextPic disable
if (m_ImagesPool.Count >= 1) {
for (int i = 0; i < m_ImagesPool.Count; i++) {

View File

@ -1,6 +1,8 @@
/// Credit Melang
/// Sourced from - http://forum.unity3d.com/members/melang.593409/
/// NOT supported in Unity 2022
#if !UNITY_2022_1_OR_NEWER
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
@ -60,3 +62,4 @@ namespace UnityEngine.UI.Extensions
}
}
}
#endif

View File

@ -1,6 +1,7 @@
/// Credit Titinious (https://github.com/Titinious)
/// Sourced from - https://github.com/Titinious/CurlyUI
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
@ -284,7 +285,9 @@ namespace UnityEngine.UI.Extensions
}
}
public void Refresh()
public void Refresh() { Invoke(nameof(Refreshx), 0.3f); }
private void Refreshx()
{
ReportSet();

View File

@ -4,14 +4,24 @@
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
#endif
[AddComponentMenu("UI/Effects/Extensions/Curly UI Text")]
public class CUIText : CUIGraphic
{
public override void ReportSet()
{
if (uiGraphic == null)
{
#if UNITY_2022_1_OR_NEWER
uiGraphic = GetComponent<TMPro.TMP_Text>();
#else
uiGraphic = GetComponent<Text>();
#endif
}
base.ReportSet();
}

View File

@ -3,7 +3,12 @@
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(Text), typeof(RectTransform))]
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
#endif
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Effects/Extensions/Curved Text")]
public class CurvedText : BaseMeshEffect
{

View File

@ -4,7 +4,12 @@
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(Text), typeof(RectTransform))]
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
#endif
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Effects/Extensions/Cylinder Text")]
public class CylinderText : BaseMeshEffect
{

View File

@ -81,8 +81,12 @@ namespace UnityEngine.UI.Extensions
List<UIVertex> verts = new List<UIVertex>();
vh.GetUIVertexStream(verts);
Text text = GetComponent<Text>();
if (text == null)
#if UNITY_2022_1_OR_NEWER
var text = GetComponent<TMPro.TMP_Text>();
#else
var text = GetComponent<Text>();
#endif
if (text == null)
{
Debug.LogWarning("LetterSpacing: Missing Text component");
return;
@ -93,29 +97,52 @@ namespace UnityEngine.UI.Extensions
float letterOffset = spacing * (float)text.fontSize / 100f;
float alignmentFactor = 0;
int glyphIdx = 0;
switch (text.alignment)
{
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
alignmentFactor = 0f;
break;
case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
alignmentFactor = 0.5f;
break;
case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
alignmentFactor = 1f;
break;
}
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
#if UNITY_2022_1_OR_NEWER
switch (text.alignment)
{
case TMPro.TextAlignmentOptions.BottomLeft:
case TMPro.TextAlignmentOptions.MidlineLeft:
case TMPro.TextAlignmentOptions.TopLeft:
alignmentFactor = 0f;
break;
case TMPro.TextAlignmentOptions.BottomJustified:
case TMPro.TextAlignmentOptions.MidlineJustified:
case TMPro.TextAlignmentOptions.TopJustified:
alignmentFactor = 0.5f;
break;
case TMPro.TextAlignmentOptions.BottomRight:
case TMPro.TextAlignmentOptions.MidlineRight:
case TMPro.TextAlignmentOptions.TopRight:
alignmentFactor = 1f;
break;
}
#else
switch (text.alignment)
{
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
alignmentFactor = 0f;
break;
case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
alignmentFactor = 0.5f;
break;
case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
alignmentFactor = 1f;
break;
}
#endif
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
{
string line = lines[lineIdx];
float lineOffset = (line.Length -1) * letterOffset * alignmentFactor;

View File

@ -46,7 +46,11 @@ using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Effects/Extensions/Mono Spacing")]
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
#endif
[RequireComponent(typeof(RectTransform))]
///Summary
/// Note, Vertex Count has changed in 5.2.1+, is now 6 (two tris) instead of 4 (tri strip).
@ -58,13 +62,21 @@ namespace UnityEngine.UI.Extensions
public bool UseHalfCharWidth = false;
private RectTransform rectTransform;
#if UNITY_2022_1_OR_NEWER
private TMPro.TMP_Text text;
#else
private Text text;
#endif
protected MonoSpacing() { }
protected override void Awake()
{
#if UNITY_2022_1_OR_NEWER
text = GetComponent<TMPro.TMP_Text>();
#else
text = GetComponent<Text>();
#endif
if (text == null)
{
Debug.LogWarning("MonoSpacing: Missing Text component");
@ -104,29 +116,51 @@ namespace UnityEngine.UI.Extensions
float letterOffset = Spacing * (float)text.fontSize / 100f;
float alignmentFactor = 0;
int glyphIdx = 0;
switch (text.alignment)
#if UNITY_2022_1_OR_NEWER
switch (text.alignment)
{
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
case TMPro.TextAlignmentOptions.BottomLeft:
case TMPro.TextAlignmentOptions.MidlineLeft:
case TMPro.TextAlignmentOptions.TopLeft:
alignmentFactor = 0f;
break;
case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
case TMPro.TextAlignmentOptions.BottomJustified:
case TMPro.TextAlignmentOptions.MidlineJustified:
case TMPro.TextAlignmentOptions.TopJustified:
alignmentFactor = 0.5f;
break;
case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
case TMPro.TextAlignmentOptions.BottomRight:
case TMPro.TextAlignmentOptions.MidlineRight:
case TMPro.TextAlignmentOptions.TopRight:
alignmentFactor = 1f;
break;
}
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
#else
switch (text.alignment)
{
case TextAnchor.LowerLeft:
case TextAnchor.MiddleLeft:
case TextAnchor.UpperLeft:
alignmentFactor = 0f;
break;
case TextAnchor.LowerCenter:
case TextAnchor.MiddleCenter:
case TextAnchor.UpperCenter:
alignmentFactor = 0.5f;
break;
case TextAnchor.LowerRight:
case TextAnchor.MiddleRight:
case TextAnchor.UpperRight:
alignmentFactor = 1f;
break;
}
#endif
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
{
string line = lines[lineIdx];
float lineOffset = (line.Length - 1) * letterOffset * (alignmentFactor) - (alignmentFactor - 0.5f) * rectTransform.rect.width;

View File

@ -1,7 +1,9 @@
/// Credit Melang, Lee Hui
/// Sourced from - http://forum.unity3d.com/members/melang.593409/
/// GC Alloc fix - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/130
/// NOT supported in Unity 2022
#if !UNITY_2022_1_OR_NEWER
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
@ -192,4 +194,5 @@ namespace UnityEngine.UI.Extensions
}
#endif
}
}
}
#endif

View File

@ -96,10 +96,8 @@ namespace UnityEngine.UI.Extensions
{
effectRoot.SetActive(true);
}
{
}
}
void OnDestroy()
{
if (!Application.isPlaying)

View File

@ -1,4 +1,6 @@
/// Credit NemoKrad (aka Charles Humphrey) / valtain

using static System.Net.Mime.MediaTypeNames;
/// Credit NemoKrad (aka Charles Humphrey) / valtain
/// Sourced from - http://www.randomchaos.co.uk/SoftAlphaUIMask.aspx
/// Updated by valtain - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/pull-requests/33
@ -45,7 +47,11 @@ namespace UnityEngine.UI.Extensions
MaskArea = GetComponent<RectTransform>();
}
#if UNITY_2022_1_OR_NEWER
var text = GetComponent<TMPro.TMP_Text>();
#else
var text = GetComponent<Text>();
#endif
if (text != null)
{
mat = new Material(ShaderLibrary.GetShaderInstance("UI Extensions/SoftMaskShader"));

View File

@ -398,6 +398,7 @@ namespace UnityEngine.UI.Extensions
{
currentMaterial = null;
currentTexture = null;
base.OnDestroy();
}
public void StartParticleEmission()

View File

@ -29,6 +29,13 @@ namespace UnityEngine.UI.Extensions
public float centerpoint = 0.5f;
protected override void OnEnable() { base.OnEnable(); CalculateRadial(); }
protected override void OnDisable()
{
m_Tracker.Clear();
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
public override void SetLayoutHorizontal() {
}
public override void SetLayoutVertical() {

View File

@ -1,7 +1,6 @@
/// Credit setchi (https://github.com/setchi)
/// Sourced from - https://github.com/setchi/FancyScrollView
namespace UnityEngine.UI.Extensions
{
/// <summary>

View File

@ -101,7 +101,7 @@ namespace UnityEngine.UI.Extensions
/// <param name="p"><see cref="Scroller"/> のスクロール位置.</param>
void OnScrollerValueChanged(float p)
{
base.UpdatePosition(Scrollable ? ToFancyScrollViewPosition(p) : 0f);
base.UpdatePosition(ToFancyScrollViewPosition(Scrollable ? p : 0f));
if (Scroller.Scrollbar)
{
@ -161,8 +161,6 @@ namespace UnityEngine.UI.Extensions
/// <inheritdoc/>
protected override void UpdateContents(IList<TItemData> items)
{
Debug.Assert(Context.CalculateScrollSize != null);
AdjustCellIntervalAndScrollOffset();
base.UpdateContents(items);

View File

@ -53,4 +53,4 @@ namespace UnityEngine.UI.Extensions
/// <inheritdoc/>
public sealed override void SetContext(FancyScrollRectContext context) => base.SetContext(context);
}
}
}

View File

@ -329,7 +329,7 @@ namespace UnityEngine.UI.Extensions
if (hold && snap.Enable)
{
UpdateSelection(Mathf.Clamp(Mathf.RoundToInt(currentPosition), 0, totalCount - 1));
UpdateSelection(Mathf.RoundToInt(CircularPosition(currentPosition, totalCount)));
ScrollTo(Mathf.RoundToInt(currentPosition), snap.Duration, snap.Easing);
}

View File

@ -166,7 +166,6 @@ namespace UnityEngine.UI.Extensions
childSize = LayoutUtility.GetPreferredSize (child, 0);
childSize = Mathf.Min (childSize, workingSize);
childOtherSize = LayoutUtility.GetPreferredSize (child, 1);
childOtherSize = Mathf.Min (childOtherSize, workingSize);
} else if (startAxis == Axis.Vertical) {
if (invertOrder) {
index = IsRightAlign ? rectChildren.Count - 1 - i : i;
@ -175,7 +174,6 @@ namespace UnityEngine.UI.Extensions
childSize = LayoutUtility.GetPreferredSize (child, 1);
childSize = Mathf.Min (childSize, workingSize);
childOtherSize = LayoutUtility.GetPreferredSize (child, 0);
childOtherSize = Mathf.Min (childOtherSize, workingSize);
}
// If adding this element would exceed the bounds of the container,
@ -227,11 +225,11 @@ namespace UnityEngine.UI.Extensions
if (startAxis == Axis.Horizontal) {
float newOffset = CalculateRowVerticalOffset (groupHeight, offset, currentBarSpace);
currentBarSize -= spacingBetweenElements;
LayoutRow (_itemList, currentBarSize, currentBarSpace, workingSize - (ChildForceExpandWidth ? 0 : spacingBetweenElements), padding.left, newOffset, axis);
LayoutRow (_itemList, currentBarSize, currentBarSpace, workingSize, padding.left, newOffset, axis);
}else if (startAxis == Axis.Vertical) {
float newOffset = CalculateColHorizontalOffset(groupWidth, offset, currentBarSpace);
currentBarSize -= spacingBetweenElements;
LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize - (ChildForceExpandHeight ? 0 : spacingBetweenElements), newOffset, padding.top, axis);
LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize, newOffset, padding.top, axis);
}
}
@ -424,5 +422,13 @@ namespace UnityEngine.UI.Extensions
}
return max;
}
}
protected override void OnDisable()
{
m_Tracker.Clear();
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
}
}

View File

@ -114,12 +114,20 @@ namespace UnityEngine.UI.Extensions
/// <param name="WorldPositionStays">Should the world position be updated to it's parent transform?</param>
public void AddChild(GameObject GO, bool WorldPositionStays)
{
_scroll_rect.horizontalNormalizedPosition = 0;
try
{
// Rare instances of Unity bug cause error, adding try to manage it.
_scroll_rect.horizontalNormalizedPosition = 0;
}
catch { }
GO.transform.SetParent(_screensContainer, WorldPositionStays);
InitialiseChildObjectsFromScene();
DistributePages();
if (MaskArea)
{
UpdateVisible();
}
SetScrollContainerPosition();
}
@ -149,7 +157,12 @@ namespace UnityEngine.UI.Extensions
{
return;
}
_scroll_rect.horizontalNormalizedPosition = 0;
try
{
// Rare instances of Unity bug cause error, adding try to manage it.
_scroll_rect.horizontalNormalizedPosition = 0;
}
catch { }
Transform child = _screensContainer.transform.GetChild(index);
child.SetParent(null, WorldPositionStays);

View File

@ -55,6 +55,13 @@ namespace UnityEngine.UI.Extensions
CalculateRadial();
}
#endif
protected override void OnDisable()
{
m_Tracker.Clear(); // key change - do not restore - false
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
void CalculateRadial()
{
m_Tracker.Clear();

View File

@ -2,11 +2,11 @@
/// Sourced from - https://github.com/setchi/FancyScrollView
using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[Obsolete("ScrollPositionController has been replaced by the Scroller component", true)]
public class ScrollPositionController : UIBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
[SerializeField]

View File

@ -5,7 +5,6 @@
using System;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI.Extensions;
namespace UnityEngine.UI.Extensions
{
@ -14,9 +13,7 @@ namespace UnityEngine.UI.Extensions
internal Rect panelDimensions;
internal RectTransform _screensContainer;
internal bool _isVertical;
internal int _screens = 1;
internal float _scrollStartPosition;
internal float _childSize;
private float _childPos, _maskSize;
@ -27,7 +24,6 @@ namespace UnityEngine.UI.Extensions
internal bool _pointerDown = false;
internal bool _settled = true;
internal Vector3 _startPosition = new Vector3();
[Tooltip("The currently active page")]
internal int _currentPage;
internal int _previousPage;
internal int _halfNoVisibleItems;
@ -37,7 +33,7 @@ namespace UnityEngine.UI.Extensions
private int _bottomItem, _topItem;
internal bool _startEventCalled = false;
internal bool _endEventCalled = false;
internal bool _suspendEvents = false;
internal bool _suspendEvents = false;
[Serializable]
public class SelectionChangeStartEvent : UnityEvent { }
@ -68,25 +64,25 @@ namespace UnityEngine.UI.Extensions
public float transitionSpeed = 7.5f;
[Tooltip("Hard Swipe forces to swiping to the next / previous page (optional)")]
public Boolean UseHardSwipe = false;
public bool UseHardSwipe = false;
[Tooltip("Fast Swipe makes swiping page next / previous (optional)")]
public Boolean UseFastSwipe = false;
public bool UseFastSwipe = false;
[Tooltip("Swipe Delta Threshold looks at the speed of input to decide if a swipe will be initiated (optional)")]
public Boolean UseSwipeDeltaThreshold = false;
public bool UseSwipeDeltaThreshold = false;
[Tooltip("Offset for how far a swipe has to travel to initiate a page change (optional)")]
public int FastSwipeThreshold = 100;
[Tooltip("Speed at which the ScrollRect will keep scrolling before slowing down and stopping (optional)")]
public int SwipeVelocityThreshold = 100;
[Tooltip("Threshold for swipe speed to initiate a swipe, below threshold will return to closest page (optional)")]
public float SwipeDeltaThreshold = 5.0f;
[Tooltip("Use time scale instead of unscaled time (optional)")]
public Boolean UseTimeScale = true;
[Tooltip("Use time scale instead of unscaled time (optional)")]
public bool UseTimeScale = true;
[Tooltip("The visible bounds area, controls which items are visible/enabled. *Note Should use a RectMask. (optional)")]
public RectTransform MaskArea;
@ -168,7 +164,6 @@ namespace UnityEngine.UI.Extensions
private SelectionChangeEndEvent m_OnSelectionChangeEndEvent = new SelectionChangeEndEvent();
public SelectionChangeEndEvent OnSelectionChangeEndEvent { get { return m_OnSelectionChangeEndEvent; } set { m_OnSelectionChangeEndEvent = value; } }
// Use this for initialization
void Awake()
{
if (_scroll_rect == null)
@ -186,7 +181,7 @@ namespace UnityEngine.UI.Extensions
vscroll.ss = this;
}
panelDimensions = gameObject.GetComponent<RectTransform>().rect;
if (StartingScreen < 0)
{
StartingScreen = 0;
@ -315,8 +310,6 @@ namespace UnityEngine.UI.Extensions
//Function for switching screens with buttons
public void NextScreen()
{
_scroll_rect.velocity = Vector2.zero;
if (_currentPage < _screens - 1 || _isInfinite)
{
if (!_lerp) StartScreenChange();
@ -339,8 +332,6 @@ namespace UnityEngine.UI.Extensions
//Function for switching screens with buttons
public void PreviousScreen()
{
_scroll_rect.velocity = Vector2.zero;
if (_currentPage > 0 || _isInfinite)
{
if (!_lerp) StartScreenChange();
@ -419,7 +410,7 @@ namespace UnityEngine.UI.Extensions
else
{
_infiniteOffset = _screensContainer.anchoredPosition.x < 0 ? -_screensContainer.sizeDelta.x * _infiniteWindow : _screensContainer.sizeDelta.x * _infiniteWindow;
_infiniteOffset = _infiniteOffset == 0 ? 0 : _infiniteOffset < 0 ? _infiniteOffset - _childSize * _infiniteWindow : _infiniteOffset + _childSize * _infiniteWindow;
_infiniteOffset = _infiniteOffset == 0 ? 0 : _infiniteOffset < 0 ? _infiniteOffset - _childSize * _infiniteWindow : _infiniteOffset + _childSize * _infiniteWindow;
target.x = _childPos + _scrollStartPosition + _infiniteOffset;
}
}
@ -520,8 +511,15 @@ namespace UnityEngine.UI.Extensions
MaskBuffer = 1;
}
PageStep.Clamp(0, 9);
if (PageStep < 0)
{
PageStep = 0;
}
if (PageStep > 8)
{
PageStep = 9;
}
var infiniteScroll = GetComponent<UI_InfiniteScroll>();
if (ChildObjects != null && ChildObjects.Length > 0 && infiniteScroll != null && !infiniteScroll.InitByUser)
{
@ -645,4 +643,4 @@ namespace UnityEngine.UI.Extensions
#endregion
}
}
}

View File

@ -284,5 +284,11 @@ namespace UnityEngine.UI.Extensions
// Set preferredRowHeights to null to free memory
preferredRowHeights = null;
}
protected override void OnDisable()
{
m_Tracker.Clear(); // key change - do not restore - false
LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}
}
}

View File

@ -1,10 +1,12 @@
/// Credit Ges
/// Sourced from - http://forum.unity3d.com/threads/scripts-useful-4-6-scripts-collection.264161/page-3#post-2280109
using System;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[Obsolete("TileSizeFitter will be deprecated in next version as Unity has disabled this feature")]
[ExecuteInEditMode]
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("Layout/Extensions/Tile Size Fitter")]

View File

@ -0,0 +1,276 @@
/// Credit Ahmad S. Al-Faqeeh
/// Sourced from - https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/205
/// Based on the UIVerticalScroller
///
using UnityEngine.Events;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(ScrollRect))]
[AddComponentMenu("Layout/Extensions/Horizontal Scroller")]
public class UIHorizontalScroller : MonoBehaviour
{
private float[] distReposition;
private float[] distance;
[SerializeField]
[Tooltip("desired ScrollRect")]
private ScrollRect scrollRect;
[SerializeField]
[Tooltip("Elements to populate inside the scroller")]
private GameObject[] arrayOfElements;
[SerializeField]
[Tooltip("Center display area (position of zoomed content)")]
private RectTransform center;
[SerializeField]
[Tooltip("Size / spacing of elements")]
private RectTransform elementSize;
[SerializeField]
[Tooltip("Scale = 1/ (1+distance from center * shrinkage)")]
private Vector2 elementShrinkage = new Vector2(1f / 200, 1f / 200);
[SerializeField]
[Tooltip("Minimum element scale (furthest from center)")]
private Vector2 minScale = new Vector2(0.7f, 0.7f);
[SerializeField]
[Tooltip("Select the item to be in center on start. (optional)")]
private int startingIndex = -1;
[SerializeField]
[Tooltip("Stop scrolling past last element from inertia.")]
private bool stopMomentumOnEnd = true;
[SerializeField]
[Tooltip("Set Items out of center to not interactible.")]
private bool disableUnfocused = true;
[SerializeField]
[Tooltip("Button to go to the next page. (optional)")]
private GameObject scrollLeftButton;
[SerializeField]
[Tooltip("Button to go to the previous page. (optional)")]
private GameObject scrollRightButton;
[SerializeField]
[Tooltip("Event fired when a specific item is clicked, exposes index number of item. (optional)")]
private UnityEvent<int> onButtonClicked;
[SerializeField]
[Tooltip("Event fired when the focused item is Changed. (optional)")]
private UnityEvent<int> onFocusChanged;
public int FocusedElementIndex { get; private set; }
public RectTransform Center { get => center; set => center = value; }
//Scrollable area (content of desired ScrollRect)
public RectTransform ScrollingPanel { get { return scrollRect.content; } }
public string Result { get; private set; }
public UIHorizontalScroller() { }
public UIHorizontalScroller(RectTransform center, RectTransform elementSize, ScrollRect scrollRect, GameObject[] arrayOfElements)
{
this.scrollRect = scrollRect;
this.elementSize = elementSize;
this.arrayOfElements = arrayOfElements;
this.center = center;
}
public void Awake()
{
if (!scrollRect)
{
scrollRect = GetComponent<ScrollRect>();
}
if (!center)
{
Debug.LogError("Please define the RectTransform for the Center viewport of the scrollable area");
}
if (!elementSize)
{
elementSize = center;
}
if (arrayOfElements == null || arrayOfElements.Length == 0)
{
var childCount = scrollRect.content.childCount;
if (childCount > 0)
{
arrayOfElements = new GameObject[childCount];
for (int i = 0; i < childCount; i++)
{
arrayOfElements[i] = scrollRect.content.GetChild(i).gameObject;
}
}
}
}
public void Start()
{
if (scrollLeftButton)
{
scrollLeftButton.GetComponent<Button>().onClick.AddListener(() => ScrollLeft());
}
if (scrollRightButton)
{
scrollRightButton.GetComponent<Button>().onClick.AddListener(() => ScrollRight());
}
UpdateChildren(startingIndex, arrayOfElements);
}
/// <summary>
/// Recognises and resizes the children.
/// </summary>
/// <param name="startingIndex">Starting index.</param>
/// <param name="arrayOfElements">Array of elements.</param>
public void UpdateChildren(int startingIndex = -1, GameObject[] arrayOfElements = null)
{
// Set _arrayOfElements to arrayOfElements if given, otherwise to child objects of the scrolling panel.
if (arrayOfElements != null)
{
this.arrayOfElements = arrayOfElements;
}
else
{
this.arrayOfElements = new GameObject[ScrollingPanel.childCount];
for (int i = 0; i < ScrollingPanel.childCount; i++)
{
this.arrayOfElements[i] = ScrollingPanel.GetChild(i).gameObject;
}
}
// resize the elements to match elementSize rect
for (var i = 0; i < this.arrayOfElements.Length; i++)
{
AddListener(arrayOfElements[i], i);
RectTransform r = this.arrayOfElements[i].GetComponent<RectTransform>();
r.anchorMax = r.anchorMin = r.pivot = new Vector2(0.5f, 0.5f);
r.localPosition = new Vector2(i * elementSize.rect.size.x,0);
r.sizeDelta = elementSize.rect.size;
}
// prepare for scrolling
distance = new float[this.arrayOfElements.Length];
distReposition = new float[this.arrayOfElements.Length];
FocusedElementIndex = -1;
// if starting index is given, snap to respective element
if (startingIndex > -1)
{
startingIndex = startingIndex > this.arrayOfElements.Length ? this.arrayOfElements.Length - 1 : startingIndex;
SnapToElement(startingIndex);
}
}
private void AddListener(GameObject button, int index)
{
var buttonClick = button.GetComponent<Button>();
buttonClick.onClick.RemoveAllListeners();
buttonClick.onClick.AddListener(() => onButtonClicked?.Invoke(index));
}
public void Update()
{
if (arrayOfElements.Length < 1)
{
return;
}
for (var i = 0; i < arrayOfElements.Length; i++)
{
var arrayElementRT = arrayOfElements[i].GetComponent<RectTransform>();
distReposition[i] = center.position.x - arrayElementRT.position.x;
distance[i] = Mathf.Abs(distReposition[i]);
//Magnifying effect
Vector2 scale = Vector2.Max(minScale, new Vector2(1 / (1 + distance[i] * elementShrinkage.x), (1 / (1 + distance[i] * elementShrinkage.y))));
arrayElementRT.transform.localScale = new Vector3(scale.x, scale.y, 1f);
}
float minDistance = Mathf.Min(distance);
int oldFocusedElement = FocusedElementIndex;
for (var i = 0; i < arrayOfElements.Length; i++)
{
arrayOfElements[i].GetComponent<CanvasGroup>().interactable = !disableUnfocused || minDistance == distance[i];
if (minDistance == distance[i])
{
FocusedElementIndex = i;
#if UNITY_2022_1_OR_NEWER
var textComponentTxtMeshPro = arrayOfElements[i].GetComponentInChildren<TMPro.TMP_Text>();
if (textComponentTxtMeshPro != null)
{
Result = textComponentTxtMeshPro.text;
}
#else
var textComponent = arrayOfElements[i].GetComponentInChildren<Text>();
if (textComponent != null)
{
Result = textComponent.text;
}
#endif
}
}
if (FocusedElementIndex != oldFocusedElement && onFocusChanged != null)
{
onFocusChanged.Invoke(FocusedElementIndex);
}
if (!UIExtensionsInputManager.GetMouseButton(0))
{
// scroll slowly to nearest element when not dragged
ScrollingElements();
}
// stop scrolling past last element from inertia
if (stopMomentumOnEnd
&& (arrayOfElements[0].GetComponent<RectTransform>().position.x > center.position.x
|| arrayOfElements[arrayOfElements.Length - 1].GetComponent<RectTransform>().position.x < center.position.x))
{
scrollRect.velocity = Vector2.zero;
}
}
private void ScrollingElements()
{
float newX = Mathf.Lerp(ScrollingPanel.anchoredPosition.x, ScrollingPanel.anchoredPosition.x + distReposition[FocusedElementIndex], Time.deltaTime * 2f);
Vector2 newPosition = new Vector2(newX, ScrollingPanel.anchoredPosition.y);
ScrollingPanel.anchoredPosition = newPosition;
}
public void SnapToElement(int element)
{
float deltaElementPositionX = elementSize.rect.width / 1.2f * element;
Vector2 newPosition = new Vector2(-deltaElementPositionX, ScrollingPanel.anchoredPosition.y);
ScrollingPanel.anchoredPosition = newPosition;
}
public void ScrollLeft()
{
float deltaLeft = elementSize.rect.width / 1.2f;
Vector2 newPositionLeft = new Vector2(ScrollingPanel.anchoredPosition.x - deltaLeft, ScrollingPanel.anchoredPosition.y);
ScrollingPanel.anchoredPosition = Vector2.Lerp(ScrollingPanel.anchoredPosition, newPositionLeft, 1);
}
public void ScrollRight()
{
float deltaRight = elementSize.rect.width / 1.2f;// arrayOfElements[0].GetComponent<RectTransform>().rect.width;
Vector2 newPositionRight = new Vector2(ScrollingPanel.anchoredPosition.x + deltaRight, ScrollingPanel.anchoredPosition.y);
ScrollingPanel.anchoredPosition = newPositionRight;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8fe84cbf30cb0874091fd899fe1457d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -10,53 +10,69 @@ namespace UnityEngine.UI.Extensions
[AddComponentMenu("Layout/Extensions/Vertical Scroller")]
public class UIVerticalScroller : MonoBehaviour
{
[Tooltip("desired ScrollRect")]
public ScrollRect scrollRect;
[Tooltip("Center display area (position of zoomed content)")]
public RectTransform center;
[Tooltip("Size / spacing of elements")]
public RectTransform elementSize;
[Tooltip("Scale = 1/ (1+distance from center * shrinkage)")]
public Vector2 elementShrinkage = new Vector2(1f / 200, 1f / 200);
[Tooltip("Minimum element scale (furthest from center)")]
public Vector2 minScale = new Vector2(0.7f, 0.7f);
[Tooltip("Select the item to be in center on start.")]
public int startingIndex = -1;
[Tooltip("Stop scrolling past last element from inertia.")]
public bool stopMomentumOnEnd = true;
[Tooltip("Set Items out of center to not interactible.")]
public bool disableUnfocused = true;
[Tooltip("Button to go to the next page. (optional)")]
public GameObject scrollUpButton;
[Tooltip("Button to go to the previous page. (optional)")]
public GameObject scrollDownButton;
[Tooltip("Event fired when a specific item is clicked, exposes index number of item. (optional)")]
public IntEvent OnButtonClicked;
[Tooltip("Event fired when the focused item is Changed. (optional)")]
public IntEvent OnFocusChanged;
[HideInInspector]
public GameObject[] _arrayOfElements;
public int focusedElementIndex { get; private set; }
public string result { get; private set; }
private float[] distReposition;
private float[] distance;
//private int elementsDistance;
[SerializeField]
[Tooltip("desired ScrollRect")]
private ScrollRect scrollRect;
[SerializeField]
[Tooltip("Elements to populate inside the scroller")]
private GameObject[] arrayOfElements;
[SerializeField]
[Tooltip("Center display area (position of zoomed content)")]
private RectTransform center;
[SerializeField]
[Tooltip("Size / spacing of elements")]
private RectTransform elementSize;
[SerializeField]
[Tooltip("Scale = 1/ (1+distance from center * shrinkage)")]
private Vector2 elementShrinkage = new Vector2(1f / 200, 1f / 200);
[SerializeField]
[Tooltip("Minimum element scale (furthest from center)")]
private Vector2 minScale = new Vector2(0.7f, 0.7f);
[SerializeField]
[Tooltip("Select the item to be in center on start.")]
private int startingIndex = -1;
[SerializeField]
[Tooltip("Stop scrolling past last element from inertia.")]
private bool stopMomentumOnEnd = true;
[SerializeField]
[Tooltip("Set Items out of center to not interactible.")]
private bool disableUnfocused = true;
[SerializeField]
[Tooltip("Button to go to the next page. (optional)")]
private GameObject scrollUpButton;
[SerializeField]
[Tooltip("Button to go to the previous page. (optional)")]
private GameObject scrollDownButton;
[SerializeField]
[Tooltip("Event fired when a specific item is clicked, exposes index number of item. (optional)")]
private UnityEvent<int> onButtonClicked;
[SerializeField]
[Tooltip("Event fired when the focused item is Changed. (optional)")]
private UnityEvent<int> onFocusChanged;
public int FocusedElementIndex { get; private set; }
public RectTransform Center { get => center; set => center = value; }
public string Result { get; private set; }
//Scrollable area (content of desired ScrollRect)
[HideInInspector]
public RectTransform scrollingPanel{ get { return scrollRect.content; } }
/// <summary>
/// Constructor when not used as component but called from other script, don't forget to set the non-optional properties.
/// </summary>
public UIVerticalScroller()
{
}
public RectTransform ScrollingPanel{ get { return scrollRect.content; } }
/// <summary>
/// Constructor when not used as component but called from other script
@ -66,7 +82,7 @@ namespace UnityEngine.UI.Extensions
this.center = center;
this.elementSize = elementSize;
this.scrollRect = scrollRect;
_arrayOfElements = arrayOfElements;
this.arrayOfElements = arrayOfElements;
}
/// <summary>
@ -78,21 +94,28 @@ namespace UnityEngine.UI.Extensions
{
scrollRect = GetComponent<ScrollRect>();
}
if (!center)
{
Debug.LogError("Please define the RectTransform for the Center viewport of the scrollable area");
}
if (!elementSize)
{
elementSize = center;
}
if (_arrayOfElements == null || _arrayOfElements.Length == 0)
if (arrayOfElements == null || arrayOfElements.Length == 0)
{
_arrayOfElements = new GameObject[scrollingPanel.childCount];
for (int i = 0; i < scrollingPanel.childCount; i++)
var childCount = ScrollingPanel.childCount;
if (childCount > 0)
{
_arrayOfElements[i] = scrollingPanel.GetChild(i).gameObject;
}
arrayOfElements = new GameObject[childCount];
for (int i = 0; i < childCount; i++)
{
arrayOfElements[i] = ScrollingPanel.GetChild(i).gameObject;
}
}
}
}
@ -101,104 +124,114 @@ namespace UnityEngine.UI.Extensions
/// </summary>
/// <param name="startingIndex">Starting index.</param>
/// <param name="arrayOfElements">Array of elements.</param>
public void updateChildren(int startingIndex = -1, GameObject[] arrayOfElements = null)
public void UpdateChildren(int startingIndex = -1, GameObject[] arrayOfElements = null)
{
// Set _arrayOfElements to arrayOfElements if given, otherwise to child objects of the scrolling panel.
if (arrayOfElements != null)
{
_arrayOfElements = arrayOfElements;
this.arrayOfElements = arrayOfElements;
}
else
{
_arrayOfElements = new GameObject[scrollingPanel.childCount];
for (int i = 0; i < scrollingPanel.childCount; i++)
this.arrayOfElements = new GameObject[ScrollingPanel.childCount];
for (int i = 0; i < ScrollingPanel.childCount; i++)
{
_arrayOfElements[i] = scrollingPanel.GetChild(i).gameObject;
this.arrayOfElements[i] = ScrollingPanel.GetChild(i).gameObject;
}
}
// resize the elements to match elementSize rect
for (var i = 0; i < _arrayOfElements.Length; i++)
for (var i = 0; i < this.arrayOfElements.Length; i++)
{
int j = i;
_arrayOfElements[i].GetComponent<Button>().onClick.RemoveAllListeners();
if (OnButtonClicked != null)
{
_arrayOfElements[i].GetComponent<Button>().onClick.AddListener(() => OnButtonClicked.Invoke(j));
}
RectTransform r = _arrayOfElements[i].GetComponent<RectTransform>();
AddListener(arrayOfElements[i], i);
RectTransform r = this.arrayOfElements[i].GetComponent<RectTransform>();
r.anchorMax = r.anchorMin = r.pivot = new Vector2(0.5f, 0.5f);
r.localPosition = new Vector2(0, i * elementSize.rect.size.y);
r.sizeDelta = elementSize.rect.size;
}
// prepare for scrolling
distance = new float[_arrayOfElements.Length];
distReposition = new float[_arrayOfElements.Length];
focusedElementIndex = -1;
//scrollRect.scrollSensitivity = elementSize.rect.height / 5;
distance = new float[this.arrayOfElements.Length];
distReposition = new float[this.arrayOfElements.Length];
FocusedElementIndex = -1;
// if starting index is given, snap to respective element
if (startingIndex > -1)
{
startingIndex = startingIndex > _arrayOfElements.Length ? _arrayOfElements.Length - 1 : startingIndex;
startingIndex = startingIndex > this.arrayOfElements.Length ? this.arrayOfElements.Length - 1 : startingIndex;
SnapToElement(startingIndex);
}
}
private void AddListener(GameObject button, int index)
{
var buttonClick = button.GetComponent<Button>();
buttonClick.onClick.RemoveAllListeners();
buttonClick.onClick.AddListener(() => onButtonClicked?.Invoke(index));
}
public void Start()
{
if (scrollUpButton)
scrollUpButton.GetComponent<Button>().onClick.AddListener(() =>
{
ScrollUp();
});
{
scrollUpButton.GetComponent<Button>().onClick.AddListener(() => ScrollUp());
}
if (scrollDownButton)
scrollDownButton.GetComponent<Button>().onClick.AddListener(() =>
{
ScrollDown();
});
updateChildren(startingIndex, _arrayOfElements);
{
scrollDownButton.GetComponent<Button>().onClick.AddListener(() => ScrollDown());
}
UpdateChildren(startingIndex, arrayOfElements);
}
public void Update()
{
if (_arrayOfElements.Length < 1)
if (arrayOfElements.Length < 1)
{
return;
}
for (var i = 0; i < _arrayOfElements.Length; i++)
for (var i = 0; i < arrayOfElements.Length; i++)
{
distReposition[i] = center.GetComponent<RectTransform>().position.y - _arrayOfElements[i].GetComponent<RectTransform>().position.y;
var arrayElementRT = arrayOfElements[i].GetComponent<RectTransform>();
distReposition[i] = center.position.y - arrayElementRT.position.y;
distance[i] = Mathf.Abs(distReposition[i]);
//Magnifying effect
Vector2 scale = Vector2.Max(minScale, new Vector2(1 / (1 + distance[i] * elementShrinkage.x), (1 / (1 + distance[i] * elementShrinkage.y))));
_arrayOfElements[i].GetComponent<RectTransform>().transform.localScale = new Vector3(scale.x, scale.y, 1f);
arrayElementRT.transform.localScale = new Vector3(scale.x, scale.y, 1f);
}
// detect focused element
float minDistance = Mathf.Min(distance);
int oldFocusedElement = focusedElementIndex;
for (var i = 0; i < _arrayOfElements.Length; i++)
int oldFocusedElement = FocusedElementIndex;
for (var i = 0; i < arrayOfElements.Length; i++)
{
_arrayOfElements[i].GetComponent<CanvasGroup>().interactable = !disableUnfocused || minDistance == distance[i];
arrayOfElements[i].GetComponent<CanvasGroup>().interactable = !disableUnfocused || minDistance == distance[i];
if (minDistance == distance[i])
{
focusedElementIndex = i;
result = _arrayOfElements[i].GetComponentInChildren<Text>().text;
FocusedElementIndex = i;
#if UNITY_2022_1_OR_NEWER
var textComponentTxtMeshPro = arrayOfElements[i].GetComponentInChildren<TMPro.TMP_Text>();
if (textComponentTxtMeshPro != null)
{
Result = textComponentTxtMeshPro.text;
}
#else
var textComponent = arrayOfElements[i].GetComponentInChildren<Text>();
if (textComponent != null)
{
Result = textComponent.text;
}
#endif
}
}
if (focusedElementIndex != oldFocusedElement && OnFocusChanged != null)
{
OnFocusChanged.Invoke(focusedElementIndex);
}
if (FocusedElementIndex != oldFocusedElement)
{
onFocusChanged?.Invoke(FocusedElementIndex);
}
if (!UIExtensionsInputManager.GetMouseButton(0))
{
@ -206,11 +239,10 @@ namespace UnityEngine.UI.Extensions
ScrollingElements();
}
// stop scrolling past last element from inertia
if (stopMomentumOnEnd
&& (_arrayOfElements[0].GetComponent<RectTransform>().position.y > center.position.y
|| _arrayOfElements[_arrayOfElements.Length - 1].GetComponent<RectTransform>().position.y < center.position.y))
&& (arrayOfElements[0].GetComponent<RectTransform>().position.y > center.position.y
|| arrayOfElements[arrayOfElements.Length - 1].GetComponent<RectTransform>().position.y < center.position.y))
{
scrollRect.velocity = Vector2.zero;
}
@ -218,37 +250,30 @@ namespace UnityEngine.UI.Extensions
private void ScrollingElements()
{
float newY = Mathf.Lerp(scrollingPanel.anchoredPosition.y, scrollingPanel.anchoredPosition.y + distReposition[focusedElementIndex], Time.deltaTime * 2f);
Vector2 newPosition = new Vector2(scrollingPanel.anchoredPosition.x, newY);
scrollingPanel.anchoredPosition = newPosition;
float newY = Mathf.Lerp(ScrollingPanel.anchoredPosition.y, ScrollingPanel.anchoredPosition.y + distReposition[FocusedElementIndex], Time.deltaTime * 2f);
Vector2 newPosition = new Vector2(ScrollingPanel.anchoredPosition.x, newY);
ScrollingPanel.anchoredPosition = newPosition;
}
public void SnapToElement(int element)
{
float deltaElementPositionY = elementSize.rect.height * element;
Vector2 newPosition = new Vector2(scrollingPanel.anchoredPosition.x, -deltaElementPositionY);
scrollingPanel.anchoredPosition = newPosition;
Vector2 newPosition = new Vector2(ScrollingPanel.anchoredPosition.x, -deltaElementPositionY);
ScrollingPanel.anchoredPosition = newPosition;
}
public void ScrollUp()
{
float deltaUp = elementSize.rect.height / 1.2f;
Vector2 newPositionUp = new Vector2(scrollingPanel.anchoredPosition.x, scrollingPanel.anchoredPosition.y - deltaUp);
scrollingPanel.anchoredPosition = Vector2.Lerp(scrollingPanel.anchoredPosition, newPositionUp, 1);
Vector2 newPositionUp = new Vector2(ScrollingPanel.anchoredPosition.x, ScrollingPanel.anchoredPosition.y - deltaUp);
ScrollingPanel.anchoredPosition = Vector2.Lerp(ScrollingPanel.anchoredPosition, newPositionUp, 1);
}
public void ScrollDown()
{
float deltaDown = elementSize.rect.height / 1.2f;
Vector2 newPositionDown = new Vector2(scrollingPanel.anchoredPosition.x, scrollingPanel.anchoredPosition.y + deltaDown);
scrollingPanel.anchoredPosition = newPositionDown;
}
[System.Serializable]
public class IntEvent:UnityEvent<int>
{
Vector2 newPositionDown = new Vector2(ScrollingPanel.anchoredPosition.x, ScrollingPanel.anchoredPosition.y + deltaDown);
ScrollingPanel.anchoredPosition = newPositionDown;
}
}
}

View File

@ -114,7 +114,13 @@ namespace UnityEngine.UI.Extensions
/// <param name="WorldPositionStays">Should the world position be updated to it's parent transform?</param>
public void AddChild(GameObject GO, bool WorldPositionStays)
{
_scroll_rect.verticalNormalizedPosition = 0;
try
{
// Rare instances of Unity bug cause error, adding try to manage it.
_scroll_rect.verticalNormalizedPosition = 0;
}
catch { }
GO.transform.SetParent(_screensContainer, WorldPositionStays);
InitialiseChildObjectsFromScene();
DistributePages();
@ -148,7 +154,12 @@ namespace UnityEngine.UI.Extensions
{
return;
}
_scroll_rect.verticalNormalizedPosition = 0;
try
{
// Rare instances of Unity bug cause error, adding try to manage it.
_scroll_rect.verticalNormalizedPosition = 0;
}
catch { }
Transform child = _screensContainer.transform.GetChild(index);
child.SetParent(null, WorldPositionStays);

View File

@ -155,6 +155,12 @@ namespace UnityEngine.UI.Extensions
SetVerticesDirty();
}
public void SetArc(float arc)
{
Arc = arc;
SetVerticesDirty();
}
public void SetArcSteps(int steps)
{
ArcSteps = steps;

View File

@ -111,10 +111,18 @@ namespace UnityEngine.UI.Extensions
set
{
if (m_points == value)
return;
m_points = value;
SetAllDirty();
if (m_points == value) return;
if (value == null || value.Length == 0)
{
m_points = new Vector2[1];
}
else
{
m_points = value;
}
SetAllDirty();
}
}

View File

@ -0,0 +1,146 @@
/// Credit Steve Westhoff, jack.sydorenko, firagon
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/324
/// Refactored and updated for performance from UILineRenderer by Steve Westhoff
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Primitives/UILineRendererFIFO")]
[RequireComponent(typeof(RectTransform))]
public class UILineRendererFIFO : UIPrimitiveBase
{
private static readonly Vector2[] middleUvs = new[] { new Vector2(0.5f, 0), new Vector2(0.5f, 1), new Vector2(0.5f, 1), new Vector2(0.5f, 0) };
private List<Vector2> addedPoints = new List<Vector2>();
private bool needsResize;
[SerializeField, Tooltip("Thickness of the line")]
private float lineThickness = 1;
[SerializeField, Tooltip("Points to draw lines between\n Can be improved using the Resolution Option")]
private List<Vector2> points = new List<Vector2>();
[SerializeField, Tooltip("Segments to be drawn\n This is a list of arrays of points")]
private List<UIVertex[]> segments = new List<UIVertex[]>();
/// <summary>
/// Thickness of the line
/// </summary>
public float LineThickness
{
get { return lineThickness; }
set { lineThickness = value; SetAllDirty(); }
}
/// <summary>
/// Points to be drawn in the line.
/// </summary>
/// <remarks>Don't add points to the list directly, use the add / remove functions</remarks>
public List<Vector2> Points
{
get
{
return points;
}
set
{
if (points == value)
return;
points = value;
SetAllDirty();
}
}
/// <summary>
/// Adds to head
/// </summary>
/// <param name="point"></param>
public void AddPoint(Vector2 point) {
points.Add(point);
addedPoints.Add(point);
}
/// <summary>
/// Removes from tail (FIFO)
/// </summary>
public void RemovePoint() {
points.RemoveAt(0);
needsResize = true;
}
/// <summary>
/// Clear all the points from the LineRenderer
/// </summary>
public void ClearPoints()
{
segments.Clear();
points.Clear();
addedPoints.Clear();
needsResize = false;
}
public void Resize() {
needsResize = true;
}
protected override void OnPopulateMesh(VertexHelper vertexHelper) {
vertexHelper.Clear();
if(needsResize) {
needsResize = false;
segments.Clear();
addedPoints = new List<Vector2>(points);
}
int count = addedPoints.Count;
if(count > 1) {
PopulateMesh(addedPoints, vertexHelper);
if(count % 2 == 0) {
addedPoints.Clear();
} else {
Vector2 extraPoint = addedPoints[count - 1];
addedPoints.Clear();
addedPoints.Add(extraPoint);
}
}
}
void PopulateMesh(List<Vector2> pointsToDraw, VertexHelper vertexHelper) {
if(ImproveResolution != ResolutionMode.None) {
pointsToDraw = IncreaseResolution(pointsToDraw);
}
float sizeX = rectTransform.rect.width;
float sizeY = rectTransform.rect.height;
float offsetX = -rectTransform.pivot.x * sizeX;
float offsetY = -rectTransform.pivot.y * sizeY;
for(int i = 1; i < pointsToDraw.Count; i += 2) {
Vector2 start = pointsToDraw[i - 1];
Vector2 end = pointsToDraw[i];
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
UIVertex[] segment = CreateLineSegment(start, end, segments.Count > 1 ? segments[segments.Count - 2] : null);
segments.Add(segment);
}
for(int i = 0; i < segments.Count; i++) {
vertexHelper.AddUIVertexQuad(segments[i]);
}
if(vertexHelper.currentVertCount > 64000) {
Debug.LogError("Max Verticies size is 64000, current mesh vertcies count is [" + vertexHelper.currentVertCount + "] - Cannot Draw");
vertexHelper.Clear();
}
}
UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, UIVertex[] previousVert = null) {
Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * lineThickness * 0.5f;
Vector2 v1;
Vector2 v2;
if(previousVert != null) {
v1 = new Vector2(previousVert[3].position.x, previousVert[3].position.y);
v2 = new Vector2(previousVert[2].position.x, previousVert[2].position.y);
} else {
v1 = start - offset;
v2 = start + offset;
}
return SetVbo(new[] { v1, v2, end + offset, end - offset }, middleUvs);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a3a91607af301f241b9f0a860c720b21
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -118,24 +118,6 @@ namespace UnityEngine.UI.Extensions
}
}
// /// <summary>
// /// List of Segments to be drawn.
// /// </summary>
// public List<Vector2[]> Segments
//{
// get
// {
// return m_segments;
// }
// set
// {
// m_segments = value;
// SetAllDirty();
// }
//}
public void AddPoint(Vector2 pointToAdd)
{
m_points.Add(pointToAdd);
@ -298,15 +280,6 @@ namespace UnityEngine.UI.Extensions
PopulateMesh (vh, m_points);
}
//else if (m_segments != null && m_segments.Count > 0) {
// GeneratedUVs ();
// vh.Clear ();
// for (int s = 0; s < m_segments.Count; s++) {
// Vector2[] pointsToDraw = m_segments [s];
// PopulateMesh (vh, pointsToDraw);
// }
//}
}
private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)

Some files were not shown because too many files have changed in this diff Show More