Release 2.3.0 (#429)

* Package upver for Development

* Added OnHighlightChanged and OnPressChanged events
Added getters and setters for Highlighted and Pressed

* Patch fix for UILineRenderer

* Update package preview release

* Resolves issue where the lower range value would become stuck when moved to the max value position

Resolves: https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/381/cant-move-range-slider-if-low-is-moved-to

* Updated Infinite scroll to work with content of different sizes

* Clean-up and reset pivots on scene start

* Patches from PR

* Clean up range slider unused variables

* Updated Dropdown list to NOT resize text Rect on draw

* Upgraded RangeSlider to work in both Horizontal and Verticle setups, just like regular slider.

Also fixed a minor issue with offset when dragging on the bar.

# Conflicts:
#	Runtime/Scripts/Controls/RangeSlider.cs

* Taking in fix from
https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/132

* Applying PR manually, because Bitbucket
https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/128

* Merged in fix manually because... Bitbucket
https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/pull-requests/130

* Remove old BitBucket Pipeline for GitHub

* Fixes issue #398 where the Next / Previous buttons filed to work if the ScrollSnap was previously scrolling.

Also renamed the Extension Methods scripts and added a new function.

Resolves: #398

* Resolves #397

Moved OnValidate checks which redraw the component to the RectTransformDimensionsCHanged event

* Updated UIParticleSystem access to Particles array to ensure it is more stable.
Updated some #if statements to be better future proofed

Resolves #360

* Fixed the UIConnector to safely handle when no parent canvas can be found.

Resolves #392

* Fixed issue which allowed an item marked as NOT transferable to actually be transferred between lists

Resolves #382

* Updated #if filter inclusion to 2019_1_OR_Newer

resolves:
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/411

* Updated UIVertical scroller to be 2022 compliant

Resolves:
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/410

* Updated Curly UI to wait until end of the frame to recalculate positions
Also updated Editor script to work in 2022

Resolves:
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/409

* Updated Depth Texture sampler in UI Particles Shaders

Resolves:
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/401

* Remove meta duplicates for HSVColour Picker

* Add newly generated HSV picker meta files

* Hard reset of Colour picker guids

* Updated Points to always be an array of 1 when set to nothing.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/295

* Updated Cooldown button to work with Keyboard input

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/171

* Added error handling around setting Unity UI Components for Vertical/Horizontal scrolling

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/296

* Protecting Remove too

* Added SetArc method to UICircle as requested

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/280

* Marked ScrollPositionController as Obsolete, users should use the newer Scroller component instead, will be removed in a future release.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/305

* Updated ScrollPositionControllerEditor as obsolete too

* Removed unneeded size calculation which caused some issues with mixed height/width children.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/380

* Resolved issue whereby the last row in a flow layout group would not size correctly.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/357

* Updated all components using "LayoutGroup" to override their OnDisable feature to incorporate this fix:
https://gist.github.com/randomize/73ca6d3b6aa7210073692eb5cabd537e

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/178

* Checking in new MinMaxSlider

TODO
- Finish Editor creator

* Added Editor Menu Option to create a Min/Max slider

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/270

* Marked TileSizeFitter as obsolete as Unity has made this unworkable

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/214

* Updated Editor create options to add the correct Event System Input module for the Input system used, now or old.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/378

* Updated Editor menu layout

* Updated initialisation logic to not cause an endless loop in the TabNavigationHelper

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/208

* Added new FIFO based UI Line Render when dynamic line rendering is needed (basic, no Beziers)

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/324

* Clean-up of ScrollSnapBase

* Updated "Action" use to "UnityAction" to avoid Unity issues

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/253

* Updated UIVerticalScroller for standards and added UIHorizontalScroller

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/205

* Updated ReorderableList/ReorderableListElement to prevent creating a "Fake" droppable when the item is not transferable

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/164

* Updated panel drawing for ComboBox controls and added DropdownOffset

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/393

* Base update for pointers to new version / package home

* Cleanup and ensuring the UIParticleSystem is disposed on Destroy correctly.

Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/412

* Refresh FancyScrollView with latest fixes

* Remove broken examples link

* Break Module

* Update Examples module to new home

* Updating GitHub artifacts and automation

* Updated build issue with ReorderableListElement

* Revised the Curly UI fix as it was preventing the graphic from being updated in the scene view.  Thanks to @solidsign for the update.

* Removed legacy Examples link, moving to separate repository

* Added new submodule for extracted examples

* Fix class spellings and update MultiTouchScrollRect

* Updated NonDrawingGraphic to require a CanvasRender, else it causes an error on run (and doesn't work)

- Resolves: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/420

* Add updated test flow for builds

* Fix github issue templates

* Add the Version upgrade pipeline

* Added ResetSelectableHighlight component

* Resolves issue in 2022 with the missing Text component

Fixes: https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/424

* The BIG Unity 2022 Text reorganisation

* Remove editor validation and add error checking for the ColorLabel component

* Add 2019 to the testing validation

* Switch android builds to windows

* Several lifetime feature updates for the ComboBox controls:

- Resolves startup issue that prevented the control being used (Unity changed the start order in some instances), this was causing null reference issues with comboboxes
- Added the ability to set a specific item on start and not just the first
- Added the ability to disable the dropdown to make a read-only dropdown

Resolves:
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/426
- https://github.com/Unity-UI-Extensions/com.unity.uiextensions/issues/425

* Resolved issues with DisplayAbove and using a 0 ItemsToDisplay

* Update pipelines for release

* Final checks for merge!

---------

Co-authored-by: Robert Rioja <rrioja@immersivedisplayinc.com>
Co-authored-by: Simon Jackson <darkside@xna-uk.net>
Co-authored-by: Ben MacKinnon <bilmackinnon@googlemail.com>
Co-authored-by: Simon Jackson <sjackson@ethar.com>
Co-authored-by: action <action@users.noreply.github.com>
pull/430/head^2
Simon (Darkside) Jackson 2023-02-07 14:35:43 +00:00 committed by GitHub
parent c3fd580886
commit 89403a2611
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 4976 additions and 2058 deletions

View File

@ -2,7 +2,7 @@
name: Bug report
about: Create a report to identify a potential issue
title: 'BUG: '
labels: Bug
labels: bug
assignees: ''
---

View File

@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for the Unity UI Extensions
title: 'Feature Request: '
labels: Feature Request
labels: enhancement
assignees: ''
---

View File

@ -2,7 +2,7 @@
name: Request for Information
about: Not sure how to do something, just ask.
title: 'RFI: '
labels: Question
labels: question
assignees: ''
---

View File

@ -1,4 +1,4 @@
name: Build and test UPM packages for platforms
name: Build and test UPM packages for platforms on all available Unity Versions
on:
pull_request:
@ -14,27 +14,24 @@ concurrency:
cancel-in-progress: true
jobs:
# Check Unity version requird by the package
validate-environment:
name: Get Unity Version from UPM package
uses: Unity-UI-Extensions/reusableworkflows/.github/workflows/getunityversionfrompackage.yml@main
with:
build-target: self-hosted
# Check Unity Hub and Editor Environment
Setup-Unity:
name: Validate Unity Install
needs: validate-environment
uses: Unity-UI-Extensions/reusableworkflows/.github/workflows/validateunityinstall.yml@main
with:
build-target: self-hosted
unityversion: ${{ needs.validate-environment.outputs.unityversion }}
# Run Unity unit tests defined in the package
Run-Unit-Tests:
# 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
needs: Setup-Unity
uses: Unity-UI-Extensions/reusableworkflows/.github/workflows/rununityunittests.yml@main
if: github.ref != 'refs/heads/development'
uses: ./.github/workflows/rununitysinglebuild.yml
with:
build-target: self-hosted
unityversion: ${{ needs.Setup-Unity.outputs.unityeditorversion }}
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,8 +1,7 @@
fileFormatVersion: 2
guid: 8701e045b26e51f4eb345f2ccb3c13f5
timeCreated: 1426804458
licenseType: Free
guid: c1047f9974e7ee1478bbf5490a7a62d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

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

@ -12,6 +12,7 @@ namespace UnityEngine.UI.Extensions
[CanEditMultipleObjects]
public class RangeSliderEditor : SelectableEditor
{
SerializedProperty m_Direction;
SerializedProperty m_LowHandleRect;
SerializedProperty m_HighHandleRect;
SerializedProperty m_FillRect;
@ -36,6 +37,7 @@ namespace UnityEngine.UI.Extensions
m_LowHandleRect = serializedObject.FindProperty("m_LowHandleRect");
m_HighHandleRect = serializedObject.FindProperty("m_HighHandleRect");
m_FillRect = serializedObject.FindProperty("m_FillRect");
m_Direction = serializedObject.FindProperty("m_Direction");
m_MinValue = serializedObject.FindProperty("m_MinValue");
m_MaxValue = serializedObject.FindProperty("m_MaxValue");
@ -66,6 +68,16 @@ namespace UnityEngine.UI.Extensions
if (m_LowHandleRect.objectReferenceValue != null && m_HighHandleRect.objectReferenceValue != null)
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_Direction);
if (EditorGUI.EndChangeCheck())
{
RangeSlider.Direction direction = (RangeSlider.Direction)m_Direction.enumValueIndex;
foreach (var obj in serializedObject.targetObjects)
{
RangeSlider rangeSlider = obj as RangeSlider;
rangeSlider.SetDirection(direction, true);
}
}
EditorGUILayout.PropertyField(m_MinValue);
EditorGUILayout.PropertyField(m_MaxValue);
@ -120,4 +132,3 @@ namespace UnityEngine.UI.Extensions
}
}

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

View File

@ -1,8 +1,17 @@
using UnityEngine;
#if UNITY_2019_1_OR_NEWER && !ENABLE_LEGACY_INPUT_MANAGER
#define NEW_INPUT_SYSTEM
#endif
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.UI.Extensions;
#if NEW_INPUT_SYSTEM
using UnityEngine.InputSystem.UI;
#endif
namespace UnityEditor.UI
{
/// <summary>
@ -156,7 +165,11 @@ namespace UnityEditor.UI
var eventSystem = new GameObject("EventSystem");
GameObjectUtility.SetParentAndAlign(eventSystem, parent);
esys = eventSystem.AddComponent<EventSystem>();
#if NEW_INPUT_SYSTEM
eventSystem.AddComponent<InputSystemUIInputModule>();
#else
eventSystem.AddComponent<StandaloneInputModule>();
#endif
Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);
}
@ -207,7 +220,7 @@ namespace UnityEditor.UI
#region UI Extensions "Create" Menu items
#region Scroll Snap controls
[MenuItem("GameObject/UI/Extensions/Horizontal Scroll Snap", false)]
[MenuItem("GameObject/UI/Extensions/Layout/Horizontal Scroll Snap", false)]
static public void AddHorizontalScrollSnap(MenuCommand menuCommand)
{
GameObject horizontalScrollSnapRoot = CreateUIElementRoot("Horizontal Scroll Snap", menuCommand, s_ThickGUIElementSize);
@ -272,7 +285,7 @@ namespace UnityEditor.UI
Selection.activeGameObject = horizontalScrollSnapRoot;
}
[MenuItem("GameObject/UI/Extensions/Vertical Scroll Snap", false)]
[MenuItem("GameObject/UI/Extensions/Layout/Vertical Scroll Snap", false)]
static public void AddVerticallScrollSnap(MenuCommand menuCommand)
{
GameObject verticalScrollSnapRoot = CreateUIElementRoot("Vertical Scroll Snap", menuCommand, s_ThickGUIElementSize);
@ -469,7 +482,7 @@ namespace UnityEditor.UI
#endregion
#region ContentScrollSnapHorizontal
[MenuItem("GameObject/UI/Extensions/Content Scroll Snap Horizontal", false)]
[MenuItem("GameObject/UI/Extensions/Layout/Content Scroll Snap Horizontal", false)]
static public void AddContentScrollSnapHorizontal(MenuCommand menuCommand)
{
GameObject contentScrollSnapRoot = CreateUIElementRoot("Content Scroll Snap Horizontal", menuCommand, s_ThickGUIElementSize);
@ -578,7 +591,7 @@ namespace UnityEditor.UI
#endregion
#region UIVertical Scroller
[MenuItem("GameObject/UI/Extensions/UI Vertical Scroller", false)]
[MenuItem("GameObject/UI/Extensions/Layout/UI Vertical Scroller", false)]
static public void AddUIVerticallScroller(MenuCommand menuCommand)
{
GameObject uiVerticalScrollerRoot = CreateUIElementRoot("UI Vertical Scroller", menuCommand, s_ThickGUIElementSize);
@ -607,7 +620,7 @@ namespace UnityEditor.UI
rectTransformCenter.anchorMax = new Vector2(1f, 0.6f);
rectTransformCenter.sizeDelta = Vector2.zero;
uiscr.center = uiScrollerCenter.GetComponent<RectTransform>();
uiscr.Center = uiScrollerCenter.GetComponent<RectTransform>();
//Setup Content container
RectTransform rectTransformContent = childContent.GetComponent<RectTransform>();
@ -658,8 +671,89 @@ namespace UnityEditor.UI
}
#endregion
#region UIHorizontal Scroller
[MenuItem("GameObject/UI/Extensions/Layout/UI Horizontal Scroller", false)]
static public void AddUIHorizontalScroller(MenuCommand menuCommand)
{
GameObject uiHorizontalScrollerRoot = CreateUIElementRoot("UI Horizontal Scroller", menuCommand, s_ThickGUIElementSize);
GameObject uiScrollerCenter = CreateUIObject("Center", uiHorizontalScrollerRoot);
GameObject childContent = CreateUIObject("Content", uiHorizontalScrollerRoot);
// Set RectTransform to stretch
RectTransform rectTransformScrollSnapRoot = uiHorizontalScrollerRoot.GetComponent<RectTransform>();
rectTransformScrollSnapRoot.anchorMin = new Vector2(0.5f, 0.5f);
rectTransformScrollSnapRoot.anchorMax = new Vector2(0.5f, 0.5f);
rectTransformScrollSnapRoot.anchoredPosition = Vector2.zero;
rectTransformScrollSnapRoot.sizeDelta = new Vector2(500f, 150f);
// Add required ScrollRect
ScrollRect sr = uiHorizontalScrollerRoot.AddComponent<ScrollRect>();
sr.vertical = false;
sr.horizontal = true;
sr.movementType = ScrollRect.MovementType.Unrestricted;
var uiscr = uiHorizontalScrollerRoot.AddComponent<UIHorizontalScroller>();
//Setup container center point
RectTransform rectTransformCenter = uiScrollerCenter.GetComponent<RectTransform>();
rectTransformCenter.anchorMin = new Vector2(0.3f,0f);
rectTransformCenter.anchorMax = new Vector2(0.6f,1f);
rectTransformCenter.sizeDelta = Vector2.zero;
uiscr.Center = uiScrollerCenter.GetComponent<RectTransform>();
//Setup Content container
RectTransform rectTransformContent = childContent.GetComponent<RectTransform>();
rectTransformContent.anchorMin = Vector2.zero;
rectTransformContent.anchorMax = new Vector2(1f, 1f);
rectTransformContent.sizeDelta = Vector2.zero;
sr.content = rectTransformContent;
// Add sample children
for (int i = 0; i < 10; i++)
{
GameObject childPage = CreateUIObject("Page_" + i, childContent);
GameObject childText = CreateUIObject("Text", childPage);
//Setup 1st Child
Image pageImage = childPage.AddComponent<Image>();
pageImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
pageImage.type = Image.Type.Sliced;
pageImage.color = s_DefaultSelectableColor;
RectTransform rectTransformPage = childPage.GetComponent<RectTransform>();
rectTransformPage.anchorMin = new Vector2(0.5f, 0);
rectTransformPage.anchorMax = new Vector2(0.5f, 1f);
rectTransformPage.sizeDelta = new Vector2(80f, 0f);
rectTransformPage.pivot = new Vector2(0.5f, 0.5f);
rectTransformPage.localPosition = new Vector3(80 * i, 0, 0);
childPage.AddComponent<Button>();
var childCG = childPage.AddComponent<CanvasGroup>();
childCG.interactable = false;
//Setup Text on Item
Text text = childText.AddComponent<Text>();
text.text = "Item_" + i;
text.alignment = TextAnchor.MiddleCenter;
text.color = new Color(0.196f, 0.196f, 0.196f);
//Setup Text on Item
RectTransform rectTransformPageText = childText.GetComponent<RectTransform>();
rectTransformPageText.anchorMin = new Vector2(0.5f, 0.5f);
rectTransformPageText.anchorMax = new Vector2(0.5f, 0.5f);
rectTransformPageText.pivot = new Vector2(0.5f, 0.5f);
}
Selection.activeGameObject = uiHorizontalScrollerRoot;
}
#endregion
#region UI Button
[MenuItem("GameObject/UI/Extensions/UI Button", false)]
[MenuItem("GameObject/UI/Extensions/Controls/UI Button", false)]
static public void AddUIButton(MenuCommand menuCommand)
{
GameObject uiButtonRoot = CreateUIElementRoot("UI Button", menuCommand, s_ThickGUIElementSize);
@ -689,7 +783,7 @@ namespace UnityEditor.UI
#endregion
#region UI Flippable
[MenuItem("GameObject/UI/Extensions/UI Flippable", false)]
[MenuItem("GameObject/UI/Extensions/Controls/UI Flippable", false)]
static public void AddUIFlippableImage(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("UI Flippable", menuCommand, s_ImageGUIElementSize);
@ -700,7 +794,7 @@ namespace UnityEditor.UI
#endregion
#region UI WindowBase
[MenuItem("GameObject/UI/Extensions/UI Window Base", false)]
[MenuItem("GameObject/UI/Extensions/Controls/UI Window Base", false)]
static public void AddUIWindowBase(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("UI Window Base", menuCommand, s_ThickGUIElementSize);
@ -779,7 +873,7 @@ namespace UnityEditor.UI
#endregion
#region Drop Down controls
[MenuItem("GameObject/UI/Extensions/AutoComplete ComboBox", false)]
[MenuItem("GameObject/UI/Extensions/ComboBox/AutoComplete ComboBox", false)]
static public void AddAutoCompleteComboBox(MenuCommand menuCommand)
{
GameObject autoCompleteComboBoxRoot = CreateUIElementRoot("AutoCompleteComboBox", menuCommand, s_ThickGUIElementSize);
@ -876,7 +970,7 @@ namespace UnityEditor.UI
Selection.activeGameObject = autoCompleteComboBoxRoot;
}
[MenuItem("GameObject/UI/Extensions/ComboBox", false)]
[MenuItem("GameObject/UI/Extensions/ComboBox/ComboBox", false)]
static public void AddComboBox(MenuCommand menuCommand)
{
GameObject comboBoxRoot = CreateUIElementRoot("ComboBox", menuCommand, s_ThickGUIElementSize);
@ -973,7 +1067,7 @@ namespace UnityEditor.UI
Selection.activeGameObject = comboBoxRoot;
}
[MenuItem("GameObject/UI/Extensions/DropDownList", false)]
[MenuItem("GameObject/UI/Extensions/ComboBox/DropDownList", false)]
static public void AddDropDownList(MenuCommand menuCommand)
{
GameObject dropDownListRoot = CreateUIElementRoot("DropDownList", menuCommand, s_ThickGUIElementSize);
@ -1192,7 +1286,7 @@ namespace UnityEditor.UI
#endregion
#region Progress bar
[MenuItem("GameObject/UI/Extensions/Progress Bar", false)]
[MenuItem("GameObject/UI/Extensions/Controls/Progress Bar", false)]
static public void AddSlider(MenuCommand menuCommand)
{
// Create GOs Hierarchy
@ -1816,7 +1910,7 @@ namespace UnityEditor.UI
#endregion
#region Segmented Control
[MenuItem("GameObject/UI/Extensions/Segmented Control", false)]
[MenuItem("GameObject/UI/Extensions/Controls/Segmented Control", false)]
static public void AddSegmentedControl(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("Segmented Control", menuCommand, s_ThickGUIElementSize);
@ -1847,7 +1941,7 @@ namespace UnityEditor.UI
#endregion
#region Stepper
[MenuItem("GameObject/UI/Extensions/Stepper", false)]
[MenuItem("GameObject/UI/Extensions/Sliders/Stepper", false)]
static public void AddStepper(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("Stepper", menuCommand, new Vector2(kWidth / 2, kThickHeight));
@ -1870,7 +1964,7 @@ namespace UnityEditor.UI
#endregion
#region UI Knob
[MenuItem("GameObject/UI/Extensions/UI Knob", false)]
[MenuItem("GameObject/UI/Extensions/Controls/UI Knob", false)]
static public void AddUIKnob(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("UI Knob", menuCommand, s_ImageGUIElementSize);
@ -1881,7 +1975,7 @@ namespace UnityEditor.UI
#endregion
#region TextPic
[MenuItem("GameObject/UI/Extensions/TextPic", false)]
[MenuItem("GameObject/UI/Extensions/Controls/TextPic", false)]
static public void AddTextPic(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("TextPic", menuCommand, s_ImageGUIElementSize);
@ -1891,7 +1985,7 @@ namespace UnityEditor.UI
#endregion
#region BoxSlider
[MenuItem("GameObject/UI/Extensions/Box Slider", false)]
[MenuItem("GameObject/UI/Extensions/Sliders/Box Slider", false)]
static public void AddBoxSlider(MenuCommand menuCommand)
{
@ -1927,7 +2021,7 @@ namespace UnityEditor.UI
#endregion
#region Non Drawing Graphic options
[MenuItem("GameObject/UI/Extensions/NonDrawingGraphic", false)]
[MenuItem("GameObject/UI/Extensions/Controls/NonDrawingGraphic", false)]
static public void AddNonDrawingGraphic(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("NonDrawing Graphic", menuCommand, s_ImageGUIElementSize);
@ -1935,7 +2029,7 @@ namespace UnityEditor.UI
Selection.activeGameObject = go;
}
[MenuItem("GameObject/UI/Extensions/NonDrawingGraphicClickable", false)]
[MenuItem("GameObject/UI/Extensions/Controls/NonDrawingGraphicClickable", false)]
static public void AddClickableNonDrawingGraphic(MenuCommand menuCommand)
{
GameObject go = CreateUIElementRoot("NonDrawing Graphic-Clickable", menuCommand, s_ImageGUIElementSize);
@ -1946,7 +2040,7 @@ namespace UnityEditor.UI
#endregion
#region Radial Slider
[MenuItem("GameObject/UI/Extensions/Radial Slider", false)]
[MenuItem("GameObject/UI/Extensions/Sliders/Radial Slider", false)]
static public void AddRadialSlider(MenuCommand menuCommand)
{
GameObject sliderRoot = CreateUIElementRoot("Radial Slider", menuCommand, s_ThickGUIElementSize);
@ -1984,21 +2078,21 @@ namespace UnityEditor.UI
#endregion
#region RangeSlider
[MenuItem("GameObject/UI/Extensions/Range Slider", false)]
[MenuItem("GameObject/UI/Extensions/Sliders/Range Slider", false)]
static public void AddRangeSlider(MenuCommand menuCommand)
{
GameObject rangeSliderRoot = CreateUIElementRoot("Range Slider", menuCommand, new Vector2(160, 20));
GameObject minMaxSliderRoot = CreateUIElementRoot("Range Slider", menuCommand, new Vector2(160, 20));
GameObject background = CreateUIObject("Background", rangeSliderRoot);
GameObject background = CreateUIObject("Background", minMaxSliderRoot);
GameObject fillArea = CreateUIObject("Fill Area", rangeSliderRoot);
GameObject fillArea = CreateUIObject("Fill Area", minMaxSliderRoot);
GameObject fill = CreateUIObject("Fill", fillArea);
GameObject handleSlideArea = CreateUIObject("Handle Slide Area", rangeSliderRoot);
GameObject lowHandle = CreateUIObject("Low Handle", handleSlideArea);
GameObject handleSlideArea = CreateUIObject("Handle Slide Area", minMaxSliderRoot);
GameObject minHandle = CreateUIObject("Low Handle", handleSlideArea);
GameObject highHandle = CreateUIObject("High Handle", handleSlideArea);
SetAnchorsAndStretch(rangeSliderRoot);
SetAnchorsAndStretch(minMaxSliderRoot);
Image backgroundImage = background.AddComponent<Image>();
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
backgroundImage.type = Image.Type.Sliced;
@ -2029,8 +2123,8 @@ namespace UnityEditor.UI
handleSlideRect.offsetMin = new Vector2(10, -10);
handleSlideRect.offsetMax = new Vector2(-10, 10);
RectTransform lowHandleRect = SetAnchorsAndStretch(lowHandle);
Image lowHandleImage = lowHandle.AddComponent<Image>();
RectTransform lowHandleRect = SetAnchorsAndStretch(minHandle);
Image lowHandleImage = minHandle.AddComponent<Image>();
lowHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
lowHandleRect.sizeDelta = new Vector2(20, 0);
@ -2039,7 +2133,7 @@ namespace UnityEditor.UI
highHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
highHandleRect.sizeDelta = new Vector2(20, 0);
RangeSlider rangeSlider = rangeSliderRoot.AddComponent<RangeSlider>();
RangeSlider rangeSlider = minMaxSliderRoot.AddComponent<RangeSlider>();
rangeSlider.FillRect = fillRect;
rangeSlider.LowHandleRect = lowHandleRect;
rangeSlider.HighHandleRect = highHandleRect;
@ -2047,7 +2141,7 @@ namespace UnityEditor.UI
rangeSlider.HighValue = rangeSlider.MaxValue;
rangeSlider.targetGraphic = fillImage;
Selection.activeGameObject = rangeSliderRoot;
Selection.activeGameObject = minMaxSliderRoot;
}
#endregion
@ -2062,6 +2156,90 @@ namespace UnityEditor.UI
}
#endregion
#region MinMaxSlider
[MenuItem("GameObject/UI/Extensions/Sliders/MinMax Slider", false)]
static public void AddMinMaxSlider(MenuCommand menuCommand)
{
GameObject minMaxSliderRoot = CreateUIElementRoot("Min Max Slider", menuCommand, new Vector2(390, 60));
GameObject sliderBounds = CreateUIObject("Slider Bounds", minMaxSliderRoot);
GameObject middleGraphic = CreateUIObject("Middle Graphic", minMaxSliderRoot);
GameObject minHandle = CreateUIObject("Min Handle", minMaxSliderRoot);
GameObject minHandleText = CreateUIObject("Min Text", minHandle);
GameObject maxHandle = CreateUIObject("Max Handle", minMaxSliderRoot);
GameObject maxHandleText = CreateUIObject("Max Text", maxHandle);
Image backgroundImage = minMaxSliderRoot.AddComponent<Image>();
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
backgroundImage.type = Image.Type.Sliced;
backgroundImage.fillCenter = false;
backgroundImage.color = new Color32(27, 41, 89, 255);
backgroundImage.fillCenter = true;
RectTransform sliderBoundsRect = SetAnchorsAndStretch(sliderBounds);
sliderBoundsRect.anchorMin = new Vector2(0, 0);
sliderBoundsRect.anchorMax = new Vector2(1, 1);
sliderBoundsRect.offsetMin = new Vector2(15, 0);
sliderBoundsRect.offsetMax = new Vector2(-15, 0);
RectTransform middleGraphicRect = SetAnchorsAndStretch(middleGraphic);
middleGraphicRect.anchorMin = new Vector2(0, 0);
middleGraphicRect.anchorMax = new Vector2(1, 1);
middleGraphicRect.offsetMin = new Vector2(82, 0);
middleGraphicRect.offsetMax = new Vector2(-90, 0);
Image fillImage = middleGraphic.AddComponent<Image>();
fillImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
fillImage.type = Image.Type.Sliced;
fillImage.fillCenter = true;
fillImage.color = new Color32(41, 98, 164, 255);
RectTransform minHandleRect = SetAnchorsAndStretch(minHandle);
minHandleRect.anchorMin = new Vector2(0, 0.5f);
minHandleRect.anchorMax = new Vector2(0, 0.5f);
minHandleRect.sizeDelta = new Vector2(30, 62);
minHandleRect.anchoredPosition = new Vector3(82, 0, 0);
Image minHandleImage = minHandle.AddComponent<Image>();
minHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
minHandleImage.type = Image.Type.Sliced;
minHandleImage.fillCenter = true;
RectTransform minHandleTextRect = SetAnchorsAndStretch(minHandleText);
minHandleTextRect.sizeDelta = new Vector2(70, 50);
minHandleTextRect.anchoredPosition = new Vector3(0, 60, 0);
TextMeshProUGUI minHandleTextComponent = minHandleText.AddComponent<TextMeshProUGUI>();
minHandleTextComponent.fontSize = 36;
minHandleTextComponent.alignment = TextAlignmentOptions.Center;
RectTransform maxHandleRect = SetAnchorsAndStretch(maxHandle);
maxHandleRect.anchorMin = new Vector2(1, 0.5f);
maxHandleRect.anchorMax = new Vector2(1, 0.5f);
maxHandleRect.sizeDelta = new Vector2(30, 62);
maxHandleRect.anchoredPosition = new Vector3(-82, 0, 0);
Image maxHandleImage = maxHandle.AddComponent<Image>();
maxHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
maxHandleImage.type = Image.Type.Sliced;
maxHandleImage.fillCenter = true;
RectTransform maxHandleTextRect = SetAnchorsAndStretch(maxHandleText);
maxHandleTextRect.sizeDelta = new Vector2(70, 50);
maxHandleTextRect.anchoredPosition = new Vector3(0, 60, 0);
TextMeshProUGUI maxHandleTextComponent = maxHandleText.AddComponent<TextMeshProUGUI>();
maxHandleTextComponent.fontSize = 36;
maxHandleTextComponent.alignment = TextAlignmentOptions.Center;
MinMaxSlider minMaxSlider = minMaxSliderRoot.AddComponent<MinMaxSlider>();
minMaxSlider.SliderBounds = sliderBoundsRect;
minMaxSlider.MinHandle = minHandleRect;
minMaxSlider.MaxHandle = maxHandleRect;
minMaxSlider.MiddleGraphic = middleGraphicRect;
minMaxSlider.MinText = minHandleTextComponent;
minMaxSlider.MaxText = maxHandleTextComponent;
minMaxSlider.SetValues(minMaxSlider.Values.minValue, minMaxSlider.Values.maxValue);
Selection.activeGameObject = minMaxSliderRoot;
}
#endregion
#endregion
@ -2206,6 +2384,5 @@ namespace UnityEditor.UI
}
#endregion
}
}

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

252
README.md
View File

@ -1,18 +1,10 @@
# This repository is being migrated to GitHub
# Unity UI Extensions README
The new home for this repository is:
> ## https://github.com/Unity-UI-Extensions/com.unity.uiextensions
BitBucket is just not what it used to be (workable)
## 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:
@ -20,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.
@ -36,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)
-----
@ -58,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")|
|-|-|
|||
> (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:
@ -74,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
@ -137,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:
@ -217,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,7 +2,6 @@ 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
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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,7 +3,6 @@ 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
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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,7 +2,6 @@ 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
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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,7 +2,6 @@ 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
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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,7 +2,6 @@ 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
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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,7 +3,6 @@ Properties {
_MainTex ("Particle Texture", 2D) = "white" {}
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
@ -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

@ -5,7 +5,11 @@
namespace UnityEngine.UI.Extensions.ColorPicker
{
#if UNITY_2022_1_OR_NEWER
[RequireComponent(typeof(TMPro.TMP_Text))]
#else
[RequireComponent(typeof(Text))]
#endif
public class ColorLabel : MonoBehaviour
{
public ColorPickerControl picker;
@ -18,12 +22,22 @@ public class ColorLabel : MonoBehaviour
public int precision = 0;
#if UNITY_2022_1_OR_NEWER
private TMPro.TMP_Text label;
#else
private Text label;
#endif
private void Awake()
{
#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)}");
}
}
private void OnEnable()
@ -44,14 +58,6 @@ public class ColorLabel : MonoBehaviour
}
}
#if UNITY_EDITOR
private void OnValidate()
{
label = GetComponent<Text>();
UpdateValue();
}
#endif
private void ColorChanged(Color color)
{
UpdateValue();

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,8 +59,10 @@ namespace UnityEngine.UI.Extensions.ColorPicker
private void OnDestroy()
{
if (image.texture != null)
{
DestroyImmediate(image.texture);
}
}
#if UNITY_EDITOR
private void OnValidate()

View File

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

View File

@ -1,8 +1,7 @@
fileFormatVersion: 2
guid: 3d95ce8fba3dbbf4eb14411412169b88
timeCreated: 1442747317
licenseType: Free
guid: 97950dcfb7ac51c4c95431d68ad7bea5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0

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

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

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;
@ -54,9 +52,14 @@ namespace UnityEngine.UI.Extensions
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,17 +84,17 @@ namespace UnityEngine.UI.Extensions
}
}
public bool SelectFirstItemOnStart = false;
[SerializeField]
[Tooltip("Change input text color based on matching items")]
private bool _ChangeInputTextColorBasedOnMatchingItems = false;
public bool InputColorMatching{
public bool InputColorMatching
{
get { return _ChangeInputTextColorBasedOnMatchingItems; }
set
{
_ChangeInputTextColorBasedOnMatchingItems = value;
if (_ChangeInputTextColorBasedOnMatchingItems) {
if (_ChangeInputTextColorBasedOnMatchingItems)
{
SetInputTextColor();
}
}
@ -102,36 +102,48 @@ namespace UnityEngine.UI.Extensions
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 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> {
}
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> {
}
public class SelectionValidityChangedEvent : Events.UnityEvent<bool> { }
[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()
{
@ -140,15 +152,17 @@ namespace UnityEngine.UI.Extensions
public void Start()
{
if (SelectFirstItemOnStart && AvailableOptions.Count > 0) {
ToggleDropdownPanel (false);
OnItemClicked (AvailableOptions [0]);
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
@ -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);
@ -413,7 +417,6 @@ namespace UnityEngine.UI.Extensions
Text = currText;
PruneItems(currText);
RedrawPanel();
//Debug.Log("value changed to: " + currText);
if (_panelItems.Count == 0)
{
@ -429,33 +432,41 @@ namespace UnityEngine.UI.Extensions
_selectionIsValid = _panelItems.Contains(Text);
OnSelectionChanged.Invoke(Text, _selectionIsValid);
OnSelectionTextChanged.Invoke(Text);
if(validity_changed){
if (validity_changed)
{
OnSelectionValidityChanged.Invoke(_selectionIsValid);
}
SetInputTextColor();
}
private void SetInputTextColor(){
if (InputColorMatching) {
if (_selectionIsValid) {
private void SetInputTextColor()
{
if (InputColorMatching)
{
if (_selectionIsValid)
{
_mainInput.textComponent.color = ValidSelectionTextColor;
} else if (_panelItems.Count > 0) {
}
else if (_panelItems.Count > 0)
{
_mainInput.textComponent.color = MatchingItemsRemainingTextColor;
} else {
}
else
{
_mainInput.textComponent.color = NoItemsRemainingTextColor;
}
}
}
/// <summary>
/// Toggle the drop down list
/// </summary>
/// <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)

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
[Header("Dropdown List Items")]
public List<DropDownListItem> Items;
[Header("Properties")]
[SerializeField]
private bool isActive = true;
public bool OverrideHighlighted = true;
//private bool isInitialized = false;
@ -38,9 +44,10 @@ namespace UnityEngine.UI.Extensions
private ScrollRect _scrollRect;
private List<DropDownListButton> _panelItems;
private List<DropDownListButton> _panelItems = new List<DropDownListButton>();
private GameObject _itemTemplate;
private bool _initialized;
[SerializeField]
private float _scrollBarWidth = 20.0f;
@ -69,30 +76,45 @@ namespace UnityEngine.UI.Extensions
}
}
public bool SelectFirstItemOnStart = false;
[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<int> {
}
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 (SelectFirstItemOnStart && Items.Count > 0) {
ToggleDropdownPanel (false);
OnItemClicked (0);
if (shouldSelectItemOnStart && Items.Count > 0)
{
SelectItemIndex(SelectFirstItemOnStart ? 0 : selectItemIndexOnStart);
}
RedrawPanel();
}
private bool Initialize()
{
if (_initialized) return true;
bool success = true;
try
{
@ -101,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>();
@ -118,7 +138,6 @@ namespace UnityEngine.UI.Extensions
_scrollRect.movementType = ScrollRect.MovementType.Clamped;
_scrollRect.content = _itemsPanelRT;
_itemTemplate = _rectTransform.Find("ItemTemplate").gameObject;
_itemTemplate.SetActive(false);
}
@ -128,14 +147,23 @@ namespace UnityEngine.UI.Extensions
Debug.LogError("Something is setup incorrectly with the dropdownlist component causing a Null Reference Exception");
success = false;
}
_panelItems = new List<DropDownListButton>();
_initialized = true;
RebuildPanel();
RedrawPanel();
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(index);
}
// currently just using items in the list instead of being able to add to it.
/// <summary>
/// Rebuilds the list from a new collection.
@ -169,6 +197,7 @@ namespace UnityEngine.UI.Extensions
}
Items.AddRange(ddItems);
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -179,6 +208,7 @@ namespace UnityEngine.UI.Extensions
{
Items.Add(item);
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -189,6 +219,7 @@ namespace UnityEngine.UI.Extensions
{
Items.Add(new DropDownListItem(caption: (string)item));
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -199,6 +230,7 @@ namespace UnityEngine.UI.Extensions
{
Items.Add(new DropDownListItem(image: (Sprite)item));
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -209,6 +241,7 @@ namespace UnityEngine.UI.Extensions
{
Items.Remove(item);
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -219,6 +252,7 @@ namespace UnityEngine.UI.Extensions
{
Items.Remove(new DropDownListItem(caption: (string)item));
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -229,12 +263,14 @@ namespace UnityEngine.UI.Extensions
{
Items.Remove(new DropDownListItem(image: (Sprite)item));
RebuildPanel();
RedrawPanel();
}
public void ResetItems()
{
Items.Clear();
RebuildPanel();
RedrawPanel();
}
/// <summary>
@ -244,6 +280,11 @@ namespace UnityEngine.UI.Extensions
{
if (Items.Count == 0) return;
if (!_initialized)
{
Start();
}
int indx = _panelItems.Count;
while (_panelItems.Count < Items.Count)
{
@ -300,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
{
@ -314,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);
@ -322,35 +359,38 @@ namespace UnityEngine.UI.Extensions
}
}
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);
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);
_mainButton.txt.rectTransform.offsetMax = new Vector2(4, 0);
_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 (Items.Count < 1) return;
float dropdownHeight = _rectTransform.sizeDelta.y * Mathf.Min(_itemsToDisplay, Items.Count);
if (_panelItems.Count < 1) return;
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, dropdownHeight);
_scrollPanelRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, _rectTransform.sizeDelta.x);
@ -372,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;
@ -385,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
@ -33,9 +32,9 @@ namespace UnityEngine.UI.Extensions
[Tooltip("Should items being dragged over this list have their sizes equalized?")]
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)
{

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;
@ -381,16 +367,19 @@ namespace UnityEngine.UI.Extensions
ToList = _currentReorderableListRaycasted,
ToIndex = _fakeElement.GetSiblingIndex()
};
//Send OnelementDropped Event
if (_reorderableList && _reorderableList.OnElementDropped != null)
{
_reorderableList.OnElementDropped.Invoke(args);
}
if (!isValid)
if (!isValid || (!IsTransferable && _currentReorderableListRaycasted != _reorderableList))
{
CancelDrag();
return;
}
RefreshSizes();
_draggingObject.SetParent(_currentReorderableListRaycasted.Content, false);
_draggingObject.rotation = _currentReorderableListRaycasted.transform.rotation;
@ -470,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

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

@ -1,5 +1,6 @@
fileFormatVersion: 2
guid: 8045f74f29fafa944b1539a3a1c6dc5c
guid: d7bdc7e70331fe24aba2c9549f84c657
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:

View File

@ -8,7 +8,7 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/BoxSlider")]
[AddComponentMenu("UI/Extensions/Sliders/BoxSlider")]
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
{
public enum Direction

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,50 +9,129 @@ 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
{
Horizontal,
Vertical
}
[Serializable]
public class RangeSliderEvent : UnityEvent<float, float> { }
public class RangeSliderEvent : UnityEvent<float, float>
{
}
[SerializeField]
private RectTransform m_FillRect;
[SerializeField] private RectTransform m_FillRect;
public RectTransform FillRect { get { return m_FillRect; } set { if (SetClass(ref m_FillRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
public RectTransform FillRect
{
get { return m_FillRect; }
set
{
if (SetClass(ref m_FillRect, value))
{
UpdateCachedReferences();
UpdateVisuals();
}
}
}
[SerializeField]
private RectTransform m_LowHandleRect;
[SerializeField] private RectTransform m_LowHandleRect;
public RectTransform LowHandleRect { get { return m_LowHandleRect; } set { if (SetClass(ref m_LowHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
public RectTransform LowHandleRect
{
get { return m_LowHandleRect; }
set
{
if (SetClass(ref m_LowHandleRect, value))
{
UpdateCachedReferences();
UpdateVisuals();
}
}
}
[SerializeField]
private RectTransform m_HighHandleRect;
[SerializeField] private RectTransform m_HighHandleRect;
public RectTransform HighHandleRect { get { return m_HighHandleRect; } set { if (SetClass(ref m_HighHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
public RectTransform HighHandleRect
{
get { return m_HighHandleRect; }
set
{
if (SetClass(ref m_HighHandleRect, value))
{
UpdateCachedReferences();
UpdateVisuals();
}
}
}
[Space]
[Space] [SerializeField] private Direction m_Direction = Direction.Horizontal;
[SerializeField]
private float m_MinValue = 0;
public Direction direction
{
get { return m_Direction; }
set
{
if (SetPropertyUtility.SetStruct(ref m_Direction, value)) UpdateVisuals();
}
}
public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
[SerializeField] private float m_MinValue = 0;
public float MinValue
{
get { return m_MinValue; }
set
{
if (SetStruct(ref m_MinValue, value))
{
SetLow(m_LowValue);
SetHigh(m_HighValue);
UpdateVisuals();
}
}
}
[SerializeField]
private float m_MaxValue = 1;
[SerializeField] private float m_MaxValue = 1;
public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
public float MaxValue
{
get { return m_MaxValue; }
set
{
if (SetStruct(ref m_MaxValue, value))
{
SetLow(m_LowValue);
SetHigh(m_HighValue);
UpdateVisuals();
}
}
}
[SerializeField]
private bool m_WholeNumbers = false;
[SerializeField] private bool m_WholeNumbers = false;
public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
public bool WholeNumbers
{
get { return m_WholeNumbers; }
set
{
if (SetStruct(ref m_WholeNumbers, value))
{
SetLow(m_LowValue);
SetHigh(m_HighValue);
UpdateVisuals();
}
}
}
[SerializeField] private float m_LowValue;
[SerializeField]
private float m_LowValue;
public virtual float LowValue
{
get
@ -78,6 +157,7 @@ namespace UnityEngine.UI.Extensions
{
return 0;
}
return Mathf.InverseLerp(MinValue, MaxValue, LowValue);
}
set
@ -87,8 +167,8 @@ namespace UnityEngine.UI.Extensions
}
[SerializeField]
private float m_HighValue;
[SerializeField] private float m_HighValue;
public virtual float HighValue
{
get
@ -114,6 +194,7 @@ namespace UnityEngine.UI.Extensions
{
return 0;
}
return Mathf.InverseLerp(MinValue, MaxValue, HighValue);
}
set
@ -132,10 +213,7 @@ namespace UnityEngine.UI.Extensions
SetHigh(high, false);
}
[Space]
[SerializeField]
private RangeSliderEvent m_OnValueChanged = new RangeSliderEvent();
[Space] [SerializeField] private RangeSliderEvent m_OnValueChanged = new RangeSliderEvent();
public RangeSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
@ -162,10 +240,8 @@ namespace UnityEngine.UI.Extensions
private Transform m_LowHandleTransform;
private RectTransform m_LowHandleContainerRect;
// The offset from handle position to mouse down position
private Vector2 m_LowOffset = Vector2.zero;
// The offset from handle position to mouse down position
private Vector2 m_HighOffset = Vector2.zero;
// The offset from interacted component position to mouse down position
private Vector2 m_Offset = Vector2.zero;
private DrivenRectTransformTracker m_Tracker;
@ -176,7 +252,8 @@ namespace UnityEngine.UI.Extensions
float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
protected RangeSlider()
{ }
{
}
#if UNITY_EDITOR
protected override void OnValidate()
@ -219,13 +296,15 @@ namespace UnityEngine.UI.Extensions
/// See ICanvasElement.LayoutComplete
/// </summary>
public virtual void LayoutComplete()
{ }
{
}
/// <summary>
/// See ICanvasElement.GraphicUpdateComplete
/// </summary>
public virtual void GraphicUpdateComplete()
{ }
{
}
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
{
@ -388,6 +467,13 @@ namespace UnityEngine.UI.Extensions
UpdateVisuals();
}
enum Axis
{
Horizontal = 0,
Vertical = 1
}
Axis axis { get { return m_Direction == Direction.Horizontal ? Axis.Horizontal : Axis.Vertical; } }
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
private void UpdateVisuals()
@ -407,8 +493,8 @@ namespace UnityEngine.UI.Extensions
//this is where some new magic must happen. Slider just uses a filled image
//and changes the % of fill. We must move the image anchors to be between the two handles.
anchorMin[0] = NormalizedLowValue;
anchorMax[0] = NormalizedHighValue;
anchorMin[(int)axis] = NormalizedLowValue;
anchorMax[(int)axis] = NormalizedHighValue;
m_FillRect.anchorMin = anchorMin;
m_FillRect.anchorMax = anchorMax;
@ -419,7 +505,7 @@ namespace UnityEngine.UI.Extensions
m_Tracker.Add(this, m_LowHandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[0] = anchorMax[0] = NormalizedLowValue;
anchorMin[(int)axis] = anchorMax[(int)axis] = NormalizedLowValue;
m_LowHandleRect.anchorMin = anchorMin;
m_LowHandleRect.anchorMax = anchorMax;
}
@ -429,7 +515,7 @@ namespace UnityEngine.UI.Extensions
m_Tracker.Add(this, m_HighHandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[0] = anchorMax[0] = NormalizedHighValue;
anchorMin[(int)axis] = anchorMax[(int)axis] = NormalizedHighValue;
m_HighHandleRect.anchorMin = anchorMin;
m_HighHandleRect.anchorMax = anchorMax;
}
@ -446,10 +532,10 @@ namespace UnityEngine.UI.Extensions
switch (interactionState)
{
case InteractionState.Low:
NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect, m_LowOffset);
NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect);
break;
case InteractionState.High:
NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect, m_HighOffset);
NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect);
break;
case InteractionState.Bar:
//special case
@ -460,35 +546,40 @@ namespace UnityEngine.UI.Extensions
}
}
private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect, Vector2 offset)
private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect)
{
RectTransform clickRect = containerRect ?? m_FillContainerRect;
if (clickRect != null && clickRect.rect.size[0] > 0)
if (clickRect != null && clickRect.rect.size[(int)axis] > 0)
{
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam,
out localCursor))
{
return 0f;
}
localCursor -= clickRect.rect.position;
float val = Mathf.Clamp01((localCursor - offset)[0] / clickRect.rect.size[0]);
float val = Mathf.Clamp01((localCursor - m_Offset)[(int)axis] / clickRect.rect.size[(int)axis]);
return val;
}
return 0;
}
private void CalculateBarDrag(PointerEventData eventData, Camera cam)
{
RectTransform clickRect = m_FillContainerRect;
if (clickRect != null && clickRect.rect.size[0] > 0)
if (clickRect != null && clickRect.rect.size[(int)axis] > 0)
{
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam,
out localCursor))
{
return;
}
localCursor -= clickRect.rect.position;
//now we need to get the delta drag on the bar
@ -499,7 +590,7 @@ namespace UnityEngine.UI.Extensions
//find the mid point on the current bar
float mid = (NormalizedHighValue + NormalizedLowValue) / 2;
//find where the new mid point should be
float val = Mathf.Clamp01((localCursor)[0] / clickRect.rect.size[0]);
float val = Mathf.Clamp01((localCursor - m_Offset)[(int)axis] / clickRect.rect.size[(int)axis]);
//calculate the delta
float delta = val - mid;
//check the clamp range
@ -529,29 +620,50 @@ namespace UnityEngine.UI.Extensions
if (!MayDrag(eventData))
return;
//HANDLE DRAG EVENTS
m_LowOffset = m_HighOffset = Vector2.zero;
Vector2 localMousePos;
if (m_HighHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventData.position, eventData.enterEventCamera))
m_Offset = Vector2.zero;
if(m_LowHandleRect != null && LowValue == MaxValue && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, eventData.position, eventData.enterEventCamera))
{
//dragging the high value handle
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HighHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
{
m_HighOffset = localMousePos;
SetToMoveLowValueHandle(m_LowHandleRect, eventData);
}
interactionState = InteractionState.High;
if (transition == Transition.ColorTint)
else if (m_HighHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventData.position, eventData.enterEventCamera))
{
targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
}
SetToMoveHighValueHandle(m_HighHandleRect, eventData);
}
else if (m_LowHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, eventData.position, eventData.enterEventCamera))
{
//dragging the low value handle
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_LowHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
SetToMoveLowValueHandle(m_LowHandleRect, eventData);
}
else if (m_FillRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_FillRect, eventData.position, eventData.enterEventCamera))
{
m_LowOffset = localMousePos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_FillRect, eventData.position, eventData.pressEventCamera, out var localMousePos))
{
m_Offset = localMousePos;
}
interactionState = InteractionState.Bar;
if (transition == Transition.ColorTint)
{
targetGraphic = m_FillImage;
}
}
else
{
//outside the handles, move the entire slider along
UpdateDrag(eventData, eventData.pressEventCamera);
}
base.OnPointerDown(eventData);
}
private void SetToMoveLowValueHandle(RectTransform transform, PointerEventData eventData)
{
//dragging the low value handle
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(transform, eventData.position, eventData.pressEventCamera, out var localMousePos))
{
m_Offset = localMousePos;
}
interactionState = InteractionState.Low;
if (transition == Transition.ColorTint)
@ -559,21 +671,20 @@ namespace UnityEngine.UI.Extensions
targetGraphic = m_LowHandleRect.GetComponent<Graphic>();
}
}
else
private void SetToMoveHighValueHandle(RectTransform transform, PointerEventData eventData)
{
//outside the handles, move the entire slider along
UpdateDrag(eventData, eventData.pressEventCamera);
if (eventData.pointerCurrentRaycast.gameObject == m_FillRect.gameObject)
//dragging the low value handle
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(transform, eventData.position, eventData.pressEventCamera, out var localMousePos))
{
interactionState = InteractionState.Bar;
m_Offset = localMousePos;
}
interactionState = InteractionState.High;
if (transition == Transition.ColorTint)
{
targetGraphic = m_FillImage;
targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
}
}
base.OnPointerDown(eventData);
}
public virtual void OnDrag(PointerEventData eventData)
{
@ -600,5 +711,17 @@ namespace UnityEngine.UI.Extensions
{
eventData.useDragThreshold = false;
}
public void SetDirection(Direction direction, bool includeRectLayouts)
{
Axis oldAxis = axis;
this.direction = direction;
if (!includeRectLayouts)
return;
if (axis != oldAxis)
RectTransformUtility.FlipLayoutAxes(transform as RectTransform, true, true);
}
}
}

View File

@ -9,8 +9,8 @@ using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
{
// Stepper control
[AddComponentMenu("UI/Extensions/Stepper")]
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("UI/Extensions/Sliders/Stepper")]
public class Stepper : UIBehaviour
{
private Selectable[] _sides;

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_Text = originalText;
#endif
positions.Clear();
@ -539,7 +551,9 @@ namespace UnityEngine.UI.Extensions {
// Update the quad images
updateQuad = true;
#if !UNITY_2022_1_OR_NEWER
m_DisableFontTextureRebuiltCallback = false;
#endif
}
/// <summary>
@ -664,9 +678,10 @@ namespace UnityEngine.UI.Extensions {
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,7 +81,11 @@ namespace UnityEngine.UI.Extensions
List<UIVertex> verts = new List<UIVertex>();
vh.GetUIVertexStream(verts);
Text text = GetComponent<Text>();
#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");
@ -94,6 +98,28 @@ namespace UnityEngine.UI.Extensions
float alignmentFactor = 0;
int glyphIdx = 0;
#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:
@ -114,6 +140,7 @@ namespace UnityEngine.UI.Extensions
alignmentFactor = 1f;
break;
}
#endif
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
{

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");
@ -105,6 +117,28 @@ namespace UnityEngine.UI.Extensions
float alignmentFactor = 0;
int glyphIdx = 0;
#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:
@ -125,7 +159,7 @@ namespace UnityEngine.UI.Extensions
alignmentFactor = 1f;
break;
}
#endif
for (int lineIdx=0; lineIdx < lines.Length; lineIdx++)
{
string line = lines[lineIdx];

View File

@ -1,6 +1,9 @@
/// Credit Melang
/// 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
{
@ -90,41 +93,6 @@ namespace UnityEngine.UI.Extensions
}
}
protected void ApplyShadowZeroAlloc(List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
{
UIVertex vt;
var neededCpacity = verts.Count * 2;
if (verts.Capacity < neededCpacity)
verts.Capacity = neededCpacity;
for (int i = start; i < end; ++i)
{
vt = verts[i];
verts.Add(vt);
Vector3 v = vt.position;
v.x += x;
v.y += y;
vt.position = v;
var newColor = color;
if (m_UseGraphicAlpha)
newColor.a = (byte)((newColor.a * verts[i].color.a) / 255);
vt.color = newColor;
verts[i] = vt;
}
}
protected void ApplyShadow(List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
{
var neededCpacity = verts.Count * 2;
if (verts.Capacity < neededCpacity)
verts.Capacity = neededCpacity;
ApplyShadowZeroAlloc(verts, color, start, end, x, y);
}
public override void ModifyMesh(VertexHelper vh)
{
if (!this.IsActive ())
@ -148,37 +116,76 @@ namespace UnityEngine.UI.Extensions
float distanceX = this.effectDistance.x * best_fit_adjustment;
float distanceY = this.effectDistance.y * best_fit_adjustment;
int start = 0;
int count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, distanceX, distanceY);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, distanceX, -distanceY);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, -distanceX, distanceY);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, -distanceX, -distanceY);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, distanceX, 0);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, -distanceX, 0);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, 0, distanceY);
start = count;
count = m_Verts.Count;
this.ApplyShadow (m_Verts, this.effectColor, start, m_Verts.Count, 0, -distanceY);
vh.Clear();
vh.AddUIVertexTriangleStream(m_Verts);
int start = 0;
// Apply Outline
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, distanceX, distanceY, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, distanceX, -distanceY, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, -distanceX, distanceY, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, -distanceX, -distanceY, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, distanceX, 0, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, -distanceX, 0, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, 0, distanceY, vh, start);
start += this.ApplyOutlineNoGC(m_Verts, this.effectColor, 0, -distanceY, vh, start);
// Apply self Text stuff
start += ApplyText(m_Verts, vh, start);
}
private int ApplyOutlineNoGC(List<UIVertex> verts, Color color, float x, float y, VertexHelper vh, int startIndex)
{
int length = verts.Count;
for (int i = 0; i < length; ++i)
{
UIVertex vt = verts[i];
Vector3 v = vt.position;
v.x += x;
v.y += y;
vt.position = v;
var newColor = color;
if (m_UseGraphicAlpha)
newColor.a = (byte)((newColor.a * verts[i].color.a) / 255);
vt.color = newColor;
// Tips: Since two triangles share same two vertices, in theory vertices can reduce to 4 / 6
// But VertexHelper.FillMesh forbid, so leave it be.
vh.AddVert(vt);
}
int triangleCount = length / 3;
for(int i=0; i<triangleCount; ++i)
{
int start = startIndex + 3 * i;
vh.AddTriangle(start + 0, start + 1, start + 2);
}
return length;
}
private int ApplyText(List<UIVertex> verts, VertexHelper vh, int startIndex)
{
int length = verts.Count;
for (int i = 0; i < length; ++i)
{
vh.AddVert(verts[i]);
}
int triangleCount = length / 3;
for (int i = 0; i < triangleCount; ++i)
{
int start = startIndex + 3 * i;
vh.AddTriangle(start + 0, start + 1, start + 2);
}
return length;
}
#if UNITY_EDITOR
protected override void OnValidate ()
{
@ -188,3 +195,4 @@ 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

@ -43,6 +43,22 @@ namespace UnityEngine.UI.Extensions
}
}
public ParticleSystem.Particle[] Particles
{
get
{
if (particles == null)
{
#if UNITY_5_5_OR_NEWER
particles = new ParticleSystem.Particle[pSystem.main.maxParticles];
#else
particles = new ParticleSystem.Particle[pSystem.maxParticles];
#endif
}
return particles;
}
}
protected bool Initialize()
{
// initialize members
@ -67,7 +83,9 @@ namespace UnityEngine.UI.Extensions
}
#else
if (pSystem.maxParticles > 14000)
{
pSystem.maxParticles = 14000;
}
#endif
pRenderer = pSystem.GetComponent<ParticleSystemRenderer>();
@ -97,16 +115,7 @@ namespace UnityEngine.UI.Extensions
#else
pSystem.scalingMode = ParticleSystemScalingMode.Hierarchy;
#endif
particles = null;
}
#if UNITY_5_5_OR_NEWER
if (particles == null)
particles = new ParticleSystem.Particle[pSystem.main.maxParticles];
#else
if (particles == null)
particles = new ParticleSystem.Particle[pSystem.maxParticles];
#endif
imageUV = new Vector4(0, 0, 1, 1);
@ -127,8 +136,10 @@ namespace UnityEngine.UI.Extensions
{
base.Awake();
if (!Initialize())
{
enabled = false;
}
}
protected override void OnPopulateMesh(VertexHelper vh)
@ -160,11 +171,11 @@ namespace UnityEngine.UI.Extensions
Vector2 corner1 = Vector2.zero;
Vector2 corner2 = Vector2.zero;
// iterate through current particles
int count = pSystem.GetParticles(particles);
int count = pSystem.GetParticles(Particles);
for (int i = 0; i < count; ++i)
{
ParticleSystem.Particle particle = particles[i];
ParticleSystem.Particle particle = Particles[i];
// get particle properties
#if UNITY_5_5_OR_NEWER
@ -223,7 +234,7 @@ namespace UnityEngine.UI.Extensions
frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);
int row = textureSheetAnimation.rowIndex;
#if UNITY_2020 || UNITY_2019
#if UNITY_2019_1_OR_NEWER
if (textureSheetAnimation.rowMode == ParticleSystemAnimationRowMode.Random)
#else
if (textureSheetAnimation.useRandomRow)
@ -378,8 +389,7 @@ namespace UnityEngine.UI.Extensions
}
}
}
if (material == currentMaterial)
return;
if (material == currentMaterial) { return; }
pSystem = null;
Initialize();
}
@ -388,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

@ -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)
{
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;
}
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

@ -13,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;
@ -26,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;
@ -67,13 +64,13 @@ 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;
@ -85,7 +82,7 @@ namespace UnityEngine.UI.Extensions
public float SwipeDeltaThreshold = 5.0f;
[Tooltip("Use time scale instead of unscaled time (optional)")]
public Boolean UseTimeScale = true;
public bool UseTimeScale = true;
[Tooltip("The visible bounds area, controls which items are visible/enabled. *Note Should use a RectMask. (optional)")]
public RectTransform MaskArea;
@ -167,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)

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,20 +94,27 @@ 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();
});
if (scrollDownButton)
scrollDownButton.GetComponent<Button>().onClick.AddListener(() =>
{
ScrollDown();
});
updateChildren(startingIndex, _arrayOfElements);
scrollUpButton.GetComponent<Button>().onClick.AddListener(() => ScrollUp());
}
if (scrollDownButton)
{
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;
}
}
if (focusedElementIndex != oldFocusedElement && OnFocusChanged != null)
FocusedElementIndex = i;
#if UNITY_2022_1_OR_NEWER
var textComponentTxtMeshPro = arrayOfElements[i].GetComponentInChildren<TMPro.TMP_Text>();
if (textComponentTxtMeshPro != null)
{
OnFocusChanged.Invoke(focusedElementIndex);
Result = textComponentTxtMeshPro.text;
}
#else
var textComponent = arrayOfElements[i].GetComponentInChildren<Text>();
if (textComponent != null)
{
Result = textComponent.text;
}
#endif
}
}
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)
{
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;
}
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,9 +111,17 @@ namespace UnityEngine.UI.Extensions
set
{
if (m_points == value)
return;
if (m_points == value) return;
if (value == null || value.Length == 0)
{
m_points = new Vector2[1];
}
else
{
m_points = value;
}
SetAllDirty();
}
}
@ -466,7 +474,7 @@ namespace UnityEngine.UI.Extensions
protected override void OnEnable()
{
base.OnEnable();
if (m_points.Length == 0)
if (m_points == null || m_points?.Length == 0)
{
m_points = new Vector2[1];
}

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)

View File

@ -6,6 +6,7 @@
/// - autoselect "firstSelectedGameObject" since it doesn't seem to work automatically
/// Updated 08-29-15 - On request of Issue #13 on repo, added a manual navigation order.
using System.Collections.Generic;
using UnityEngine.EventSystems;
namespace UnityEngine.UI.Extensions
@ -16,15 +17,19 @@ namespace UnityEngine.UI.Extensions
public class TabNavigationHelper : MonoBehaviour
{
private EventSystem _system;
private Selectable StartingObject;
private Selectable LastObject;
private Selectable startingObject;
private Selectable lastObject;
[Tooltip("The path to take when user is tabbing through ui components.")]
public Selectable[] NavigationPath;
[Tooltip("Use the default Unity navigation system or a manual fixed order using Navigation Path")]
public NavigationMode NavigationMode;
[Tooltip("If True, this will loop the tab order from last to first automatically")]
public bool CircularNavigation;
void Start()
{
_system = GetComponent<EventSystem>();
@ -34,24 +39,35 @@ namespace UnityEngine.UI.Extensions
}
if (NavigationMode == NavigationMode.Manual && NavigationPath.Length > 0)
{
StartingObject = NavigationPath[0].gameObject.GetComponent<Selectable>();
startingObject = NavigationPath[0].gameObject.GetComponent<Selectable>();
}
if (StartingObject == null && CircularNavigation)
if (startingObject == null && CircularNavigation)
{
SelectDefaultObject(out StartingObject);
SelectDefaultObject(out startingObject);
}
}
public void Update()
{
Selectable next = null;
if (LastObject == null && _system.currentSelectedGameObject != null)
if (lastObject == null && _system.currentSelectedGameObject != null)
{
var startingPoint = _system.currentSelectedGameObject.GetComponent<Selectable>();
var selectableItems = new Stack<Selectable>();
selectableItems.Push(startingPoint);
//Find the last selectable object
next = _system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnDown();
next = startingPoint.FindSelectableOnDown();
while (next != null)
{
LastObject = next;
if (selectableItems.Contains(next))
{
lastObject = selectableItems.Pop();
selectableItems.Clear();
break;
}
lastObject = next;
selectableItems.Push(next);
next = next.FindSelectableOnDown();
}
}
@ -76,7 +92,7 @@ namespace UnityEngine.UI.Extensions
next = _system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnUp();
if (next == null && CircularNavigation)
{
next = LastObject;
next = lastObject;
}
}
else
@ -105,7 +121,7 @@ namespace UnityEngine.UI.Extensions
next = _system.currentSelectedGameObject.GetComponent<Selectable>().FindSelectableOnDown();
if (next == null && CircularNavigation)
{
next = StartingObject;
next = startingObject;
}
}
else
@ -119,9 +135,9 @@ namespace UnityEngine.UI.Extensions
SelectDefaultObject(out next);
}
if (CircularNavigation && StartingObject == null)
if (CircularNavigation && startingObject == null)
{
StartingObject = next;
startingObject = next;
}
selectGameObject(next);
}

View File

@ -11,7 +11,11 @@ namespace UnityEngine.UI.Extensions
public int verticalPadding;
//tooltip text
#if UNITY_2022_1_OR_NEWER
public TMPro.TMP_Text thisText;
#else
public Text thisText;
#endif
//horizontal layout of the tooltip
public HorizontalLayoutGroup hlG;

View File

@ -27,7 +27,11 @@ namespace UnityEngine.UI.Extensions
public class ToolTip : MonoBehaviour
{
//text of the tooltip
#if UNITY_2022_1_OR_NEWER
private TMPro.TMP_Text _text;
#else
private Text _text;
#endif
private RectTransform _rectTransform, canvasRectTransform;
[Tooltip("The canvas used by the tooltip as positioning and scaling reference. Should usually be the root Canvas of the hierarchy this component is in")]
@ -114,7 +118,11 @@ namespace UnityEngine.UI.Extensions
canvasRectTransform = canvas.GetComponent<RectTransform>();
_layoutGroup = GetComponentInChildren<LayoutGroup>();
#if UNITY_2022_1_OR_NEWER
_text = GetComponentInChildren<TMPro.TMP_Text>();
#else
_text = GetComponentInChildren<Text>();
#endif
_inside = false;

View File

@ -2,7 +2,7 @@
namespace UnityEngine.UI.Extensions
{
public static class ExtentionMethods
public static class ExtensionMethods
{
public static T GetOrAddComponent<T>(this GameObject child) where T : Component
{
@ -29,5 +29,27 @@ namespace UnityEngine.UI.Extensions
!gameObject.hideFlags.HasFlag(HideFlags.HideInHierarchy);
// I don't care about GameObjects *inside* prefabs, just the overall prefab.
}
/// <summary>
/// Generic clamp method to limt a value between a range of values
/// </summary>
/// <typeparam name="T"><see cref="IComparable"/> data type</typeparam>
/// <param name="value">Value to clamp</param>
/// <param name="min">Minimum value</param>
/// <param name="max">Maximum value</param>
/// <returns></returns>
public static T Clamp<T>(this T value, T min, T max) where T : IComparable<T>
{
if (value.CompareTo(min) < 0)
{
value = min;
}
if (value.CompareTo(max) > 0)
{
value = max;
}
return value;
}
}
}

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