mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-13 11:20:31 +00:00
Normalize all the line endings
This commit is contained in:
514
.gitignore
vendored
514
.gitignore
vendored
@@ -1,258 +1,258 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
*.userprefs
|
*.userprefs
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
[Rr]elease/
|
[Rr]elease/
|
||||||
[Rr]eleases/
|
[Rr]eleases/
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[Ll]og/
|
[Ll]og/
|
||||||
|
|
||||||
# Visual Studio 2015 cache/options directory
|
# Visual Studio 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
#wwwroot/
|
#wwwroot/
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
[Bb]uild[Ll]og.*
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
# NUNIT
|
# NUNIT
|
||||||
*.VisualState.xml
|
*.VisualState.xml
|
||||||
TestResult.xml
|
TestResult.xml
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
# Build Results of an ATL Project
|
||||||
[Dd]ebugPS/
|
[Dd]ebugPS/
|
||||||
[Rr]eleasePS/
|
[Rr]eleasePS/
|
||||||
dlldata.c
|
dlldata.c
|
||||||
|
|
||||||
# DNX
|
# DNX
|
||||||
project.lock.json
|
project.lock.json
|
||||||
project.fragment.lock.json
|
project.fragment.lock.json
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
*_i.c
|
*_i.c
|
||||||
*_p.c
|
*_p.c
|
||||||
*_i.h
|
*_i.h
|
||||||
*.ilk
|
*.ilk
|
||||||
*.meta
|
*.meta
|
||||||
*.obj
|
*.obj
|
||||||
*.pch
|
*.pch
|
||||||
*.pdb
|
*.pdb
|
||||||
*.pgc
|
*.pgc
|
||||||
*.pgd
|
*.pgd
|
||||||
*.rsp
|
*.rsp
|
||||||
*.sbr
|
*.sbr
|
||||||
*.tlb
|
*.tlb
|
||||||
*.tli
|
*.tli
|
||||||
*.tlh
|
*.tlh
|
||||||
*.tmp
|
*.tmp
|
||||||
*.tmp_proj
|
*.tmp_proj
|
||||||
*.log
|
*.log
|
||||||
*.vspscc
|
*.vspscc
|
||||||
*.vssscc
|
*.vssscc
|
||||||
.builds
|
.builds
|
||||||
*.pidb
|
*.pidb
|
||||||
*.svclog
|
*.svclog
|
||||||
*.scc
|
*.scc
|
||||||
|
|
||||||
# Chutzpah Test files
|
# Chutzpah Test files
|
||||||
_Chutzpah*
|
_Chutzpah*
|
||||||
|
|
||||||
# Visual C++ cache files
|
# Visual C++ cache files
|
||||||
ipch/
|
ipch/
|
||||||
*.aps
|
*.aps
|
||||||
*.ncb
|
*.ncb
|
||||||
*.opendb
|
*.opendb
|
||||||
*.opensdf
|
*.opensdf
|
||||||
*.sdf
|
*.sdf
|
||||||
*.cachefile
|
*.cachefile
|
||||||
*.VC.db
|
*.VC.db
|
||||||
*.VC.VC.opendb
|
*.VC.VC.opendb
|
||||||
|
|
||||||
# Visual Studio profiler
|
# Visual Studio profiler
|
||||||
*.psess
|
*.psess
|
||||||
*.vsp
|
*.vsp
|
||||||
*.vspx
|
*.vspx
|
||||||
*.sap
|
*.sap
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
# TFS 2012 Local Workspace
|
||||||
$tf/
|
$tf/
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
# Guidance Automation Toolkit
|
||||||
*.gpState
|
*.gpState
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
# ReSharper is a .NET coding add-in
|
||||||
_ReSharper*/
|
_ReSharper*/
|
||||||
*.[Rr]e[Ss]harper
|
*.[Rr]e[Ss]harper
|
||||||
*.DotSettings.user
|
*.DotSettings.user
|
||||||
|
|
||||||
# JustCode is a .NET coding add-in
|
# JustCode is a .NET coding add-in
|
||||||
.JustCode
|
.JustCode
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
# TeamCity is a build add-in
|
||||||
_TeamCity*
|
_TeamCity*
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
# DotCover is a Code Coverage Tool
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|
||||||
# NCrunch
|
# NCrunch
|
||||||
_NCrunch_*
|
_NCrunch_*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
nCrunchTemp_*
|
nCrunchTemp_*
|
||||||
|
|
||||||
# MightyMoose
|
# MightyMoose
|
||||||
*.mm.*
|
*.mm.*
|
||||||
AutoTest.Net/
|
AutoTest.Net/
|
||||||
|
|
||||||
# Web workbench (sass)
|
# Web workbench (sass)
|
||||||
.sass-cache/
|
.sass-cache/
|
||||||
|
|
||||||
# Installshield output folder
|
# Installshield output folder
|
||||||
[Ee]xpress/
|
[Ee]xpress/
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
# DocProject is a documentation generator add-in
|
||||||
DocProject/buildhelp/
|
DocProject/buildhelp/
|
||||||
DocProject/Help/*.HxT
|
DocProject/Help/*.HxT
|
||||||
DocProject/Help/*.HxC
|
DocProject/Help/*.HxC
|
||||||
DocProject/Help/*.hhc
|
DocProject/Help/*.hhc
|
||||||
DocProject/Help/*.hhk
|
DocProject/Help/*.hhk
|
||||||
DocProject/Help/*.hhp
|
DocProject/Help/*.hhp
|
||||||
DocProject/Help/Html2
|
DocProject/Help/Html2
|
||||||
DocProject/Help/html
|
DocProject/Help/html
|
||||||
|
|
||||||
# Click-Once directory
|
# Click-Once directory
|
||||||
publish/
|
publish/
|
||||||
|
|
||||||
# Publish Web Output
|
# Publish Web Output
|
||||||
*.[Pp]ublish.xml
|
*.[Pp]ublish.xml
|
||||||
*.azurePubxml
|
*.azurePubxml
|
||||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
*.pubxml
|
*.pubxml
|
||||||
*.publishproj
|
*.publishproj
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
# in these scripts will be unencrypted
|
# in these scripts will be unencrypted
|
||||||
PublishScripts/
|
PublishScripts/
|
||||||
|
|
||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
# The packages folder can be ignored because of Package Restore
|
||||||
**/packages/*
|
**/packages/*
|
||||||
# except build/, which is used as an MSBuild target.
|
# except build/, which is used as an MSBuild target.
|
||||||
!**/packages/build/
|
!**/packages/build/
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
#!**/packages/repositories.config
|
#!**/packages/repositories.config
|
||||||
# NuGet v3's project.json files produces more ignoreable files
|
# NuGet v3's project.json files produces more ignoreable files
|
||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
# Microsoft Azure Build Output
|
||||||
csx/
|
csx/
|
||||||
*.build.csdef
|
*.build.csdef
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
# Microsoft Azure Emulator
|
||||||
ecf/
|
ecf/
|
||||||
rcf/
|
rcf/
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
# Windows Store app package directories and files
|
||||||
AppPackages/
|
AppPackages/
|
||||||
BundleArtifacts/
|
BundleArtifacts/
|
||||||
Package.StoreAssociation.xml
|
Package.StoreAssociation.xml
|
||||||
_pkginfo.txt
|
_pkginfo.txt
|
||||||
|
|
||||||
# Visual Studio cache files
|
# Visual Studio cache files
|
||||||
# files ending in .cache can be ignored
|
# files ending in .cache can be ignored
|
||||||
*.[Cc]ache
|
*.[Cc]ache
|
||||||
# but keep track of directories ending in .cache
|
# but keep track of directories ending in .cache
|
||||||
!*.[Cc]ache/
|
!*.[Cc]ache/
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
ClientBin/
|
ClientBin/
|
||||||
~$*
|
~$*
|
||||||
*~
|
*~
|
||||||
*.dbmdl
|
*.dbmdl
|
||||||
*.dbproj.schemaview
|
*.dbproj.schemaview
|
||||||
*.pfx
|
*.pfx
|
||||||
*.publishsettings
|
*.publishsettings
|
||||||
node_modules/
|
node_modules/
|
||||||
orleans.codegen.cs
|
orleans.codegen.cs
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
#bower_components/
|
#bower_components/
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
# RIA/Silverlight projects
|
||||||
Generated_Code/
|
Generated_Code/
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
# Backup & report files from converting an old project file
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
# because we have git ;-)
|
# because we have git ;-)
|
||||||
_UpgradeReport_Files/
|
_UpgradeReport_Files/
|
||||||
Backup*/
|
Backup*/
|
||||||
UpgradeLog*.XML
|
UpgradeLog*.XML
|
||||||
UpgradeLog*.htm
|
UpgradeLog*.htm
|
||||||
|
|
||||||
# SQL Server files
|
# SQL Server files
|
||||||
*.mdf
|
*.mdf
|
||||||
*.ldf
|
*.ldf
|
||||||
|
|
||||||
# Business Intelligence projects
|
# Business Intelligence projects
|
||||||
*.rdl.data
|
*.rdl.data
|
||||||
*.bim.layout
|
*.bim.layout
|
||||||
*.bim_*.settings
|
*.bim_*.settings
|
||||||
|
|
||||||
# Microsoft Fakes
|
# Microsoft Fakes
|
||||||
FakesAssemblies/
|
FakesAssemblies/
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
# GhostDoc plugin setting file
|
||||||
*.GhostDoc.xml
|
*.GhostDoc.xml
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
# Node.js Tools for Visual Studio
|
||||||
.ntvs_analysis.dat
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
# Visual Studio 6 build log
|
||||||
*.plg
|
*.plg
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
# Visual Studio 6 workspace options file
|
||||||
*.opt
|
*.opt
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# Visual Studio LightSwitch build output
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
**/*.Server/GeneratedArtifacts
|
**/*.Server/GeneratedArtifacts
|
||||||
**/*.Server/ModelManifest.xml
|
**/*.Server/ModelManifest.xml
|
||||||
_Pvt_Extensions
|
_Pvt_Extensions
|
||||||
|
|
||||||
# Paket dependency manager
|
# Paket dependency manager
|
||||||
.paket/paket.exe
|
.paket/paket.exe
|
||||||
paket-files/
|
paket-files/
|
||||||
|
|
||||||
# FAKE - F# Make
|
# FAKE - F# Make
|
||||||
.fake/
|
.fake/
|
||||||
|
|
||||||
# JetBrains Rider
|
# JetBrains Rider
|
||||||
.idea/
|
.idea/
|
||||||
*.sln.iml
|
*.sln.iml
|
||||||
|
|
||||||
# CodeRush
|
# CodeRush
|
||||||
.cr/
|
.cr/
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
# Python Tools for Visual Studio (PTVS)
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
30
.travis.yml
30
.travis.yml
@@ -1,15 +1,15 @@
|
|||||||
language: csharp
|
language: csharp
|
||||||
solution: osu-framework.sln
|
solution: osu-framework.sln
|
||||||
mono:
|
mono:
|
||||||
- latest
|
- latest
|
||||||
before_install:
|
before_install:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
install:
|
install:
|
||||||
- nuget restore osu-framework.sln
|
- nuget restore osu-framework.sln
|
||||||
- nuget install NUnit.Runners -Version 3.4.1 -OutputDirectory testrunner
|
- nuget install NUnit.Runners -Version 3.4.1 -OutputDirectory testrunner
|
||||||
script:
|
script:
|
||||||
- xbuild osu-framework.sln
|
- xbuild osu-framework.sln
|
||||||
- |
|
- |
|
||||||
mono \
|
mono \
|
||||||
./testrunner/NUnit.ConsoleRunner.3.4.1/tools/nunit3-console.exe \
|
./testrunner/NUnit.ConsoleRunner.3.4.1/tools/nunit3-console.exe \
|
||||||
./osu.Framework.Tests/osu.Framework.Tests.csproj
|
./osu.Framework.Tests/osu.Framework.Tests.csproj
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
|
|
||||||
namespace SampleGame
|
namespace SampleGame
|
||||||
{
|
{
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main()
|
public static void Main()
|
||||||
{
|
{
|
||||||
using (Game game = new SampleGame())
|
using (Game game = new SampleGame())
|
||||||
using (GameHost host = Host.GetSuitableHost(@"sample-game"))
|
using (GameHost host = Host.GetSuitableHost(@"sample-game"))
|
||||||
host.Run(game);
|
host.Run(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
|
||||||
namespace SampleGame
|
namespace SampleGame
|
||||||
{
|
{
|
||||||
internal class SampleGame : Game
|
internal class SampleGame : Game
|
||||||
{
|
{
|
||||||
private Box box;
|
private Box box;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Add(box = new Box
|
Add(box = new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(150, 150),
|
Size = new Vector2(150, 150),
|
||||||
Colour = Color4.Tomato
|
Colour = Color4.Tomato
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
box.Rotation += (float)Time.Elapsed / 10;
|
box.Rotation += (float)Time.Elapsed / 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,63 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.27004.2002
|
VisualStudioVersion = 15.0.27004.2002
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework", "osu.Framework\osu.Framework.csproj", "{C76BF5B3-985E-4D39-95FE-97C9C879B83A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleGame", "SampleGame\SampleGame.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleGame", "SampleGame\SampleGame.csproj", "{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.Tests", "osu.Framework.Tests\osu.Framework.Tests.csproj", "{79803407-6F50-484F-93F5-641911EABD8A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Framework.Tests", "osu.Framework.Tests\osu.Framework.Tests.csproj", "{79803407-6F50-484F-93F5-641911EABD8A}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C76BF5B3-985E-4D39-95FE-97C9C879B83A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{79803407-6F50-484F-93F5-641911EABD8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
Policies = $0
|
Policies = $0
|
||||||
$0.TextStylePolicy = $1
|
$0.TextStylePolicy = $1
|
||||||
$1.EolMarker = Windows
|
$1.EolMarker = Windows
|
||||||
$1.inheritsSet = VisualStudio
|
$1.inheritsSet = VisualStudio
|
||||||
$1.inheritsScope = text/plain
|
$1.inheritsScope = text/plain
|
||||||
$1.scope = text/x-csharp
|
$1.scope = text/x-csharp
|
||||||
$0.CSharpFormattingPolicy = $2
|
$0.CSharpFormattingPolicy = $2
|
||||||
$2.IndentSwitchSection = True
|
$2.IndentSwitchSection = True
|
||||||
$2.NewLinesForBracesInProperties = True
|
$2.NewLinesForBracesInProperties = True
|
||||||
$2.NewLinesForBracesInAccessors = True
|
$2.NewLinesForBracesInAccessors = True
|
||||||
$2.NewLinesForBracesInAnonymousMethods = True
|
$2.NewLinesForBracesInAnonymousMethods = True
|
||||||
$2.NewLinesForBracesInControlBlocks = True
|
$2.NewLinesForBracesInControlBlocks = True
|
||||||
$2.NewLinesForBracesInAnonymousTypes = True
|
$2.NewLinesForBracesInAnonymousTypes = True
|
||||||
$2.NewLinesForBracesInObjectCollectionArrayInitializers = True
|
$2.NewLinesForBracesInObjectCollectionArrayInitializers = True
|
||||||
$2.NewLinesForBracesInLambdaExpressionBody = True
|
$2.NewLinesForBracesInLambdaExpressionBody = True
|
||||||
$2.NewLineForElse = True
|
$2.NewLineForElse = True
|
||||||
$2.NewLineForCatch = True
|
$2.NewLineForCatch = True
|
||||||
$2.NewLineForFinally = True
|
$2.NewLineForFinally = True
|
||||||
$2.NewLineForMembersInObjectInit = True
|
$2.NewLineForMembersInObjectInit = True
|
||||||
$2.NewLineForMembersInAnonymousTypes = True
|
$2.NewLineForMembersInAnonymousTypes = True
|
||||||
$2.NewLineForClausesInQuery = True
|
$2.NewLineForClausesInQuery = True
|
||||||
$2.SpacingAfterMethodDeclarationName = False
|
$2.SpacingAfterMethodDeclarationName = False
|
||||||
$2.SpaceAfterMethodCallName = False
|
$2.SpaceAfterMethodCallName = False
|
||||||
$2.SpaceBeforeOpenSquareBracket = False
|
$2.SpaceBeforeOpenSquareBracket = False
|
||||||
$2.inheritsSet = Mono
|
$2.inheritsSet = Mono
|
||||||
$2.inheritsScope = text/x-csharp
|
$2.inheritsScope = text/x-csharp
|
||||||
$2.scope = text/x-csharp
|
$2.scope = text/x-csharp
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests
|
namespace osu.Framework.Tests
|
||||||
{
|
{
|
||||||
internal class AutomatedVisualTestGame : TestGame
|
internal class AutomatedVisualTestGame : TestGame
|
||||||
{
|
{
|
||||||
public AutomatedVisualTestGame()
|
public AutomatedVisualTestGame()
|
||||||
{
|
{
|
||||||
Add(new TestBrowserTestRunner(new TestBrowser()));
|
Add(new TestBrowserTestRunner(new TestBrowser()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableBoolTest
|
public class BindableBoolTest
|
||||||
{
|
{
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
public void TestSet(bool value)
|
public void TestSet(bool value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableBool { Value = value };
|
var bindable = new BindableBool { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("True", true)]
|
[TestCase("True", true)]
|
||||||
[TestCase("true", true)]
|
[TestCase("true", true)]
|
||||||
[TestCase("False", false)]
|
[TestCase("False", false)]
|
||||||
[TestCase("false", false)]
|
[TestCase("false", false)]
|
||||||
[TestCase("1", true)]
|
[TestCase("1", true)]
|
||||||
[TestCase("0", false)]
|
[TestCase("0", false)]
|
||||||
public void TestParsingString(string value, bool expected)
|
public void TestParsingString(string value, bool expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableBool();
|
var bindable = new BindableBool();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
public void TestParsingBoolean(bool value)
|
public void TestParsingBoolean(bool value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableBool();
|
var bindable = new BindableBool();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableDoubleTest
|
public class BindableDoubleTest
|
||||||
{
|
{
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105.123)]
|
[TestCase(-105.123)]
|
||||||
[TestCase(105.123)]
|
[TestCase(105.123)]
|
||||||
[TestCase(double.MinValue)]
|
[TestCase(double.MinValue)]
|
||||||
[TestCase(double.MaxValue)]
|
[TestCase(double.MaxValue)]
|
||||||
public void TestSet(double value)
|
public void TestSet(double value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableDouble { Value = value };
|
var bindable = new BindableDouble { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", 0f)]
|
[TestCase("0", 0f)]
|
||||||
[TestCase("1", 1f)]
|
[TestCase("1", 1f)]
|
||||||
[TestCase("-0", 0f)]
|
[TestCase("-0", 0f)]
|
||||||
[TestCase("-105.123", -105.123)]
|
[TestCase("-105.123", -105.123)]
|
||||||
[TestCase("105.123", 105.123)]
|
[TestCase("105.123", 105.123)]
|
||||||
public void TestParsingString(string value, double expected)
|
public void TestParsingString(string value, double expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableDouble();
|
var bindable = new BindableDouble();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", -10, 10, 0)]
|
[TestCase("0", -10, 10, 0)]
|
||||||
[TestCase("1", -10, 10, 1)]
|
[TestCase("1", -10, 10, 1)]
|
||||||
[TestCase("-0", -10, 10, 0)]
|
[TestCase("-0", -10, 10, 0)]
|
||||||
[TestCase("-105.123", -10, 10, -10)]
|
[TestCase("-105.123", -10, 10, -10)]
|
||||||
[TestCase("105.123", -10, 10, 10)]
|
[TestCase("105.123", -10, 10, 10)]
|
||||||
public void TestParsingStringWithRange(string value, double minValue, double maxValue, double expected)
|
public void TestParsingStringWithRange(string value, double minValue, double maxValue, double expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableDouble { MinValue = minValue, MaxValue = maxValue };
|
var bindable = new BindableDouble { MinValue = minValue, MaxValue = maxValue };
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105.123)]
|
[TestCase(-105.123)]
|
||||||
[TestCase(105.123)]
|
[TestCase(105.123)]
|
||||||
[TestCase(double.MinValue)]
|
[TestCase(double.MinValue)]
|
||||||
[TestCase(double.MaxValue)]
|
[TestCase(double.MaxValue)]
|
||||||
public void TestParsingDouble(double value)
|
public void TestParsingDouble(double value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableDouble();
|
var bindable = new BindableDouble();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableEnumTest
|
public class BindableEnumTest
|
||||||
{
|
{
|
||||||
[TestCase(TestEnum.Value1)]
|
[TestCase(TestEnum.Value1)]
|
||||||
[TestCase(TestEnum.Value2)]
|
[TestCase(TestEnum.Value2)]
|
||||||
[TestCase(TestEnum.Value1 - 1)]
|
[TestCase(TestEnum.Value1 - 1)]
|
||||||
[TestCase(TestEnum.Value2 + 1)]
|
[TestCase(TestEnum.Value2 + 1)]
|
||||||
public void TestSet(TestEnum value)
|
public void TestSet(TestEnum value)
|
||||||
{
|
{
|
||||||
var bindable = new Bindable<TestEnum> { Value = value };
|
var bindable = new Bindable<TestEnum> { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("Value1", TestEnum.Value1)]
|
[TestCase("Value1", TestEnum.Value1)]
|
||||||
[TestCase("Value2", TestEnum.Value2)]
|
[TestCase("Value2", TestEnum.Value2)]
|
||||||
[TestCase("-1", TestEnum.Value1 - 1)]
|
[TestCase("-1", TestEnum.Value1 - 1)]
|
||||||
[TestCase("2", TestEnum.Value2 + 1)]
|
[TestCase("2", TestEnum.Value2 + 1)]
|
||||||
public void TestParsingString(string value, TestEnum expected)
|
public void TestParsingString(string value, TestEnum expected)
|
||||||
{
|
{
|
||||||
var bindable = new Bindable<TestEnum>();
|
var bindable = new Bindable<TestEnum>();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(TestEnum.Value1)]
|
[TestCase(TestEnum.Value1)]
|
||||||
[TestCase(TestEnum.Value2)]
|
[TestCase(TestEnum.Value2)]
|
||||||
[TestCase(TestEnum.Value1 - 1)]
|
[TestCase(TestEnum.Value1 - 1)]
|
||||||
[TestCase(TestEnum.Value2 + 1)]
|
[TestCase(TestEnum.Value2 + 1)]
|
||||||
public void TestParsingEnum(TestEnum value)
|
public void TestParsingEnum(TestEnum value)
|
||||||
{
|
{
|
||||||
var bindable = new Bindable<TestEnum>();
|
var bindable = new Bindable<TestEnum>();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TestEnum
|
public enum TestEnum
|
||||||
{
|
{
|
||||||
Value1 = 0,
|
Value1 = 0,
|
||||||
Value2 = 1
|
Value2 = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableFloatTest
|
public class BindableFloatTest
|
||||||
{
|
{
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105.123f)]
|
[TestCase(-105.123f)]
|
||||||
[TestCase(105.123f)]
|
[TestCase(105.123f)]
|
||||||
[TestCase(float.MinValue)]
|
[TestCase(float.MinValue)]
|
||||||
[TestCase(float.MaxValue)]
|
[TestCase(float.MaxValue)]
|
||||||
public void TestSet(float value)
|
public void TestSet(float value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableFloat { Value = value };
|
var bindable = new BindableFloat { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", 0f)]
|
[TestCase("0", 0f)]
|
||||||
[TestCase("1", 1f)]
|
[TestCase("1", 1f)]
|
||||||
[TestCase("-0", 0f)]
|
[TestCase("-0", 0f)]
|
||||||
[TestCase("-105.123", -105.123f)]
|
[TestCase("-105.123", -105.123f)]
|
||||||
[TestCase("105.123", 105.123f)]
|
[TestCase("105.123", 105.123f)]
|
||||||
public void TestParsingString(string value, float expected)
|
public void TestParsingString(string value, float expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableFloat();
|
var bindable = new BindableFloat();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", -10, 10, 0)]
|
[TestCase("0", -10, 10, 0)]
|
||||||
[TestCase("1", -10, 10, 1)]
|
[TestCase("1", -10, 10, 1)]
|
||||||
[TestCase("-0", -10, 10, 0)]
|
[TestCase("-0", -10, 10, 0)]
|
||||||
[TestCase("-105.123", -10, 10, -10)]
|
[TestCase("-105.123", -10, 10, -10)]
|
||||||
[TestCase("105.123", -10, 10, 10)]
|
[TestCase("105.123", -10, 10, 10)]
|
||||||
public void TestParsingStringWithRange(string value, float minValue, float maxValue, float expected)
|
public void TestParsingStringWithRange(string value, float minValue, float maxValue, float expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableFloat { MinValue = minValue, MaxValue = maxValue };
|
var bindable = new BindableFloat { MinValue = minValue, MaxValue = maxValue };
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105.123f)]
|
[TestCase(-105.123f)]
|
||||||
[TestCase(105.123f)]
|
[TestCase(105.123f)]
|
||||||
[TestCase(float.MinValue)]
|
[TestCase(float.MinValue)]
|
||||||
[TestCase(float.MaxValue)]
|
[TestCase(float.MaxValue)]
|
||||||
public void TestParsingFloat(float value)
|
public void TestParsingFloat(float value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableFloat();
|
var bindable = new BindableFloat();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableIntTest
|
public class BindableIntTest
|
||||||
{
|
{
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105)]
|
[TestCase(-105)]
|
||||||
[TestCase(105)]
|
[TestCase(105)]
|
||||||
[TestCase(int.MinValue)]
|
[TestCase(int.MinValue)]
|
||||||
[TestCase(int.MaxValue)]
|
[TestCase(int.MaxValue)]
|
||||||
public void TestSet(int value)
|
public void TestSet(int value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableInt { Value = value };
|
var bindable = new BindableInt { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", 0)]
|
[TestCase("0", 0)]
|
||||||
[TestCase("1", 1)]
|
[TestCase("1", 1)]
|
||||||
[TestCase("-0", 0)]
|
[TestCase("-0", 0)]
|
||||||
[TestCase("-105", -105)]
|
[TestCase("-105", -105)]
|
||||||
[TestCase("105", 105)]
|
[TestCase("105", 105)]
|
||||||
public void TestParsingString(string value, int expected)
|
public void TestParsingString(string value, int expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableInt();
|
var bindable = new BindableInt();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", -10, 10, 0)]
|
[TestCase("0", -10, 10, 0)]
|
||||||
[TestCase("1", -10, 10, 1)]
|
[TestCase("1", -10, 10, 1)]
|
||||||
[TestCase("-0", -10, 10, 0)]
|
[TestCase("-0", -10, 10, 0)]
|
||||||
[TestCase("-105", -10, 10, -10)]
|
[TestCase("-105", -10, 10, -10)]
|
||||||
[TestCase("105", -10, 10, 10)]
|
[TestCase("105", -10, 10, 10)]
|
||||||
public void TestParsingStringWithRange(string value, int minValue, int maxValue, int expected)
|
public void TestParsingStringWithRange(string value, int minValue, int maxValue, int expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableInt { MinValue = minValue, MaxValue = maxValue };
|
var bindable = new BindableInt { MinValue = minValue, MaxValue = maxValue };
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105)]
|
[TestCase(-105)]
|
||||||
[TestCase(105)]
|
[TestCase(105)]
|
||||||
[TestCase(int.MinValue)]
|
[TestCase(int.MinValue)]
|
||||||
[TestCase(int.MaxValue)]
|
[TestCase(int.MaxValue)]
|
||||||
public void TestParsingInt(int value)
|
public void TestParsingInt(int value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableInt();
|
var bindable = new BindableInt();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,66 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableLongTest
|
public class BindableLongTest
|
||||||
{
|
{
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105)]
|
[TestCase(-105)]
|
||||||
[TestCase(105)]
|
[TestCase(105)]
|
||||||
[TestCase(long.MinValue)]
|
[TestCase(long.MinValue)]
|
||||||
[TestCase(long.MaxValue)]
|
[TestCase(long.MaxValue)]
|
||||||
public void TestSet(long value)
|
public void TestSet(long value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableLong { Value = value };
|
var bindable = new BindableLong { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", 0)]
|
[TestCase("0", 0)]
|
||||||
[TestCase("1", 1)]
|
[TestCase("1", 1)]
|
||||||
[TestCase("-0", 0)]
|
[TestCase("-0", 0)]
|
||||||
[TestCase("-105", -105)]
|
[TestCase("-105", -105)]
|
||||||
[TestCase("105", 105)]
|
[TestCase("105", 105)]
|
||||||
public void TestParsingString(string value, long expected)
|
public void TestParsingString(string value, long expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableLong();
|
var bindable = new BindableLong();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("0", -10, 10, 0)]
|
[TestCase("0", -10, 10, 0)]
|
||||||
[TestCase("1", -10, 10, 1)]
|
[TestCase("1", -10, 10, 1)]
|
||||||
[TestCase("-0", -10, 10, 0)]
|
[TestCase("-0", -10, 10, 0)]
|
||||||
[TestCase("-105", -10, 10, -10)]
|
[TestCase("-105", -10, 10, -10)]
|
||||||
[TestCase("105", -10, 10, 10)]
|
[TestCase("105", -10, 10, 10)]
|
||||||
public void TestParsingStringWithRange(string value, long minValue, long maxValue, long expected)
|
public void TestParsingStringWithRange(string value, long minValue, long maxValue, long expected)
|
||||||
{
|
{
|
||||||
var bindable = new BindableLong { MinValue = minValue, MaxValue = maxValue };
|
var bindable = new BindableLong { MinValue = minValue, MaxValue = maxValue };
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(expected, bindable.Value);
|
Assert.AreEqual(expected, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(0)]
|
[TestCase(0)]
|
||||||
[TestCase(-0)]
|
[TestCase(-0)]
|
||||||
[TestCase(1)]
|
[TestCase(1)]
|
||||||
[TestCase(-105)]
|
[TestCase(-105)]
|
||||||
[TestCase(105)]
|
[TestCase(105)]
|
||||||
[TestCase(long.MinValue)]
|
[TestCase(long.MinValue)]
|
||||||
[TestCase(long.MaxValue)]
|
[TestCase(long.MaxValue)]
|
||||||
public void TestParsingLong(long value)
|
public void TestParsingLong(long value)
|
||||||
{
|
{
|
||||||
var bindable = new BindableLong();
|
var bindable = new BindableLong();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Bindables
|
namespace osu.Framework.Tests.Bindables
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class BindableStringTest
|
public class BindableStringTest
|
||||||
{
|
{
|
||||||
[TestCase("")]
|
[TestCase("")]
|
||||||
[TestCase(null)]
|
[TestCase(null)]
|
||||||
[TestCase("this is a string")]
|
[TestCase("this is a string")]
|
||||||
public void TestSet(string value)
|
public void TestSet(string value)
|
||||||
{
|
{
|
||||||
var bindable = new Bindable<string> { Value = value };
|
var bindable = new Bindable<string> { Value = value };
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("")]
|
[TestCase("")]
|
||||||
[TestCase("null")]
|
[TestCase("null")]
|
||||||
[TestCase("this is a string")]
|
[TestCase("this is a string")]
|
||||||
public void TestParsingString(string value)
|
public void TestParsingString(string value)
|
||||||
{
|
{
|
||||||
var bindable = new Bindable<string>();
|
var bindable = new Bindable<string>();
|
||||||
bindable.Parse(value);
|
bindable.Parse(value);
|
||||||
|
|
||||||
Assert.AreEqual(value, bindable.Value);
|
Assert.AreEqual(value, bindable.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.IO
|
namespace osu.Framework.Tests.IO
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSortedListSerialization
|
public class TestSortedListSerialization
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestUnsortedSerialization()
|
public void TestUnsortedSerialization()
|
||||||
{
|
{
|
||||||
var original = new SortedList<int>();
|
var original = new SortedList<int>();
|
||||||
original.AddRange(new[] { 1, 2, 3, 4, 5, 6 });
|
original.AddRange(new[] { 1, 2, 3, 4, 5, 6 });
|
||||||
|
|
||||||
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
||||||
|
|
||||||
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
||||||
for (int i = 0; i < original.Count; i++)
|
for (int i = 0; i < original.Count; i++)
|
||||||
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSortedSerialization()
|
public void TestSortedSerialization()
|
||||||
{
|
{
|
||||||
var original = new SortedList<int>();
|
var original = new SortedList<int>();
|
||||||
original.AddRange(new[] { 6, 5, 4, 3, 2, 1 });
|
original.AddRange(new[] { 6, 5, 4, 3, 2, 1 });
|
||||||
|
|
||||||
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
||||||
|
|
||||||
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
||||||
for (int i = 0; i < original.Count; i++)
|
for (int i = 0; i < original.Count; i++)
|
||||||
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEmptySerialization()
|
public void TestEmptySerialization()
|
||||||
{
|
{
|
||||||
var original = new SortedList<int>();
|
var original = new SortedList<int>();
|
||||||
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
var deserialized = JsonConvert.DeserializeObject<SortedList<int>>(JsonConvert.SerializeObject(original));
|
||||||
|
|
||||||
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestCustomComparer()
|
public void TestCustomComparer()
|
||||||
{
|
{
|
||||||
int compare(int i1, int i2) => i2.CompareTo(i1);
|
int compare(int i1, int i2) => i2.CompareTo(i1);
|
||||||
|
|
||||||
var original = new SortedList<int>(compare);
|
var original = new SortedList<int>(compare);
|
||||||
original.AddRange(new[] { 1, 2, 3, 4, 5, 6 });
|
original.AddRange(new[] { 1, 2, 3, 4, 5, 6 });
|
||||||
|
|
||||||
var deserialized = new SortedList<int>(compare);
|
var deserialized = new SortedList<int>(compare);
|
||||||
JsonConvert.PopulateObject(JsonConvert.SerializeObject(original), deserialized);
|
JsonConvert.PopulateObject(JsonConvert.SerializeObject(original), deserialized);
|
||||||
|
|
||||||
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
Assert.AreEqual(original.Count, deserialized.Count, "Counts are not equal");
|
||||||
for (int i = 0; i < original.Count; i++)
|
for (int i = 0; i < original.Count; i++)
|
||||||
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
Assert.AreEqual(original[i], deserialized[i], $"Item at index {i} differs");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,438 +1,438 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using HttpMethod = osu.Framework.IO.Network.HttpMethod;
|
using HttpMethod = osu.Framework.IO.Network.HttpMethod;
|
||||||
using WebRequest = osu.Framework.IO.Network.WebRequest;
|
using WebRequest = osu.Framework.IO.Network.WebRequest;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.IO
|
namespace osu.Framework.Tests.IO
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestWebRequest
|
public class TestWebRequest
|
||||||
{
|
{
|
||||||
private const string valid_get_url = "httpbin.org/get";
|
private const string valid_get_url = "httpbin.org/get";
|
||||||
private const string invalid_get_url = "a.ppy.shhhhh";
|
private const string invalid_get_url = "a.ppy.shhhhh";
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestValidGet([Values("http", "https")] string protocol, [Values(true, false)] bool async)
|
public void TestValidGet([Values("http", "https")] string protocol, [Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var url = $"{protocol}://httpbin.org/get";
|
var url = $"{protocol}://httpbin.org/get";
|
||||||
var request = new JsonWebRequest<HttpBinGetResponse>(url) { Method = HttpMethod.GET };
|
var request = new JsonWebRequest<HttpBinGetResponse>(url) { Method = HttpMethod.GET };
|
||||||
|
|
||||||
bool hasThrown = false;
|
bool hasThrown = false;
|
||||||
request.Failed += exception => hasThrown = exception != null;
|
request.Failed += exception => hasThrown = exception != null;
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.DoesNotThrowAsync(request.PerformAsync);
|
Assert.DoesNotThrowAsync(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsFalse(request.Aborted);
|
Assert.IsFalse(request.Aborted);
|
||||||
|
|
||||||
var responseObject = request.ResponseObject;
|
var responseObject = request.ResponseObject;
|
||||||
|
|
||||||
Assert.IsTrue(responseObject != null);
|
Assert.IsTrue(responseObject != null);
|
||||||
Assert.IsTrue(responseObject.Headers.UserAgent == "osu!");
|
Assert.IsTrue(responseObject.Headers.UserAgent == "osu!");
|
||||||
Assert.IsTrue(responseObject.Url == url);
|
Assert.IsTrue(responseObject.Url == url);
|
||||||
|
|
||||||
Assert.IsFalse(hasThrown);
|
Assert.IsFalse(hasThrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestInvalidGetExceptions([Values("http", "https")] string protocol, [Values(true, false)] bool async)
|
public void TestInvalidGetExceptions([Values("http", "https")] string protocol, [Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new WebRequest($"{protocol}://{invalid_get_url}") { Method = HttpMethod.GET };
|
var request = new WebRequest($"{protocol}://{invalid_get_url}") { Method = HttpMethod.GET };
|
||||||
|
|
||||||
Exception finishedException = null;
|
Exception finishedException = null;
|
||||||
request.Failed += exception => finishedException = exception;
|
request.Failed += exception => finishedException = exception;
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.ThrowsAsync<HttpRequestException>(request.PerformAsync);
|
Assert.ThrowsAsync<HttpRequestException>(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.Throws<HttpRequestException>(request.Perform);
|
Assert.Throws<HttpRequestException>(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(request.ResponseString == null);
|
Assert.IsTrue(request.ResponseString == null);
|
||||||
Assert.IsNotNull(finishedException);
|
Assert.IsNotNull(finishedException);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestBadStatusCode([Values(true, false)] bool async)
|
public void TestBadStatusCode([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new WebRequest("https://httpbin.org/hidden-basic-auth/user/passwd");
|
var request = new WebRequest("https://httpbin.org/hidden-basic-auth/user/passwd");
|
||||||
|
|
||||||
bool hasThrown = false;
|
bool hasThrown = false;
|
||||||
request.Failed += exception => hasThrown = exception != null;
|
request.Failed += exception => hasThrown = exception != null;
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.ThrowsAsync<WebException>(request.PerformAsync);
|
Assert.ThrowsAsync<WebException>(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.Throws<WebException>(request.Perform);
|
Assert.Throws<WebException>(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
Assert.IsEmpty(request.ResponseString);
|
Assert.IsEmpty(request.ResponseString);
|
||||||
|
|
||||||
Assert.IsTrue(hasThrown);
|
Assert.IsTrue(hasThrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests aborting the <see cref="WebRequest"/> after response has been received from the server
|
/// Tests aborting the <see cref="WebRequest"/> after response has been received from the server
|
||||||
/// but before data has been read.
|
/// but before data has been read.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestAbortReceive([Values(true, false)] bool async)
|
public void TestAbortReceive([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
||||||
|
|
||||||
bool hasThrown = false;
|
bool hasThrown = false;
|
||||||
request.Failed += exception => hasThrown = exception != null;
|
request.Failed += exception => hasThrown = exception != null;
|
||||||
request.Started += () => request.Abort();
|
request.Started += () => request.Abort();
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.DoesNotThrowAsync(request.PerformAsync);
|
Assert.DoesNotThrowAsync(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(request.ResponseObject == null);
|
Assert.IsTrue(request.ResponseObject == null);
|
||||||
|
|
||||||
Assert.IsFalse(hasThrown);
|
Assert.IsFalse(hasThrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests aborting the <see cref="WebRequest"/> before the request is sent to the server.
|
/// Tests aborting the <see cref="WebRequest"/> before the request is sent to the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestAbortRequest()
|
public void TestAbortRequest()
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
||||||
|
|
||||||
bool hasThrown = false;
|
bool hasThrown = false;
|
||||||
request.Failed += exception => hasThrown = exception != null;
|
request.Failed += exception => hasThrown = exception != null;
|
||||||
|
|
||||||
#pragma warning disable 4014
|
#pragma warning disable 4014
|
||||||
request.PerformAsync();
|
request.PerformAsync();
|
||||||
#pragma warning restore 4014
|
#pragma warning restore 4014
|
||||||
|
|
||||||
Assert.DoesNotThrow(request.Abort);
|
Assert.DoesNotThrow(request.Abort);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(request.ResponseObject == null);
|
Assert.IsTrue(request.ResponseObject == null);
|
||||||
|
|
||||||
Assert.IsFalse(hasThrown);
|
Assert.IsFalse(hasThrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests being able to abort + restart a request.
|
/// Tests being able to abort + restart a request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestRestartAfterAbort([Values(true, false)] bool async)
|
public void TestRestartAfterAbort([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
||||||
|
|
||||||
bool hasThrown = false;
|
bool hasThrown = false;
|
||||||
request.Failed += exception => hasThrown = exception != null;
|
request.Failed += exception => hasThrown = exception != null;
|
||||||
|
|
||||||
#pragma warning disable 4014
|
#pragma warning disable 4014
|
||||||
request.PerformAsync();
|
request.PerformAsync();
|
||||||
#pragma warning restore 4014
|
#pragma warning restore 4014
|
||||||
|
|
||||||
Assert.DoesNotThrow(request.Abort);
|
Assert.DoesNotThrow(request.Abort);
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.ThrowsAsync<InvalidOperationException>(request.PerformAsync);
|
Assert.ThrowsAsync<InvalidOperationException>(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.Throws<InvalidOperationException>(request.Perform);
|
Assert.Throws<InvalidOperationException>(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
var responseObject = request.ResponseObject;
|
var responseObject = request.ResponseObject;
|
||||||
|
|
||||||
Assert.IsTrue(responseObject == null);
|
Assert.IsTrue(responseObject == null);
|
||||||
Assert.IsFalse(hasThrown);
|
Assert.IsFalse(hasThrown);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that specifically-crafted <see cref="WebRequest"/> is completed after one timeout.
|
/// Tests that specifically-crafted <see cref="WebRequest"/> is completed after one timeout.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestOneTimeout()
|
public void TestOneTimeout()
|
||||||
{
|
{
|
||||||
var request = new DelayedWebRequest
|
var request = new DelayedWebRequest
|
||||||
{
|
{
|
||||||
Method = HttpMethod.GET,
|
Method = HttpMethod.GET,
|
||||||
Timeout = 1000,
|
Timeout = 1000,
|
||||||
Delay = 2
|
Delay = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
Exception thrownException = null;
|
Exception thrownException = null;
|
||||||
request.Failed += e => thrownException = e;
|
request.Failed += e => thrownException = e;
|
||||||
request.CompleteInvoked = () => request.Delay = 0;
|
request.CompleteInvoked = () => request.Delay = 0;
|
||||||
|
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsFalse(request.Aborted);
|
Assert.IsFalse(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(thrownException == null);
|
Assert.IsTrue(thrownException == null);
|
||||||
Assert.AreEqual(WebRequest.MAX_RETRIES, request.RetryCount);
|
Assert.AreEqual(WebRequest.MAX_RETRIES, request.RetryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a <see cref="WebRequest"/> will only timeout a maximum of <see cref="WebRequest.MAX_RETRIES"/> times before being aborted.
|
/// Tests that a <see cref="WebRequest"/> will only timeout a maximum of <see cref="WebRequest.MAX_RETRIES"/> times before being aborted.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestFailTimeout()
|
public void TestFailTimeout()
|
||||||
{
|
{
|
||||||
var request = new WebRequest("https://httpbin.org/delay/4")
|
var request = new WebRequest("https://httpbin.org/delay/4")
|
||||||
{
|
{
|
||||||
Method = HttpMethod.GET,
|
Method = HttpMethod.GET,
|
||||||
Timeout = 1000
|
Timeout = 1000
|
||||||
};
|
};
|
||||||
|
|
||||||
Exception thrownException = null;
|
Exception thrownException = null;
|
||||||
request.Failed += e => thrownException = e;
|
request.Failed += e => thrownException = e;
|
||||||
|
|
||||||
Assert.Throws<WebException>(request.Perform);
|
Assert.Throws<WebException>(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsTrue(request.Aborted);
|
Assert.IsTrue(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(thrownException != null);
|
Assert.IsTrue(thrownException != null);
|
||||||
Assert.AreEqual(WebRequest.MAX_RETRIES, request.RetryCount);
|
Assert.AreEqual(WebRequest.MAX_RETRIES, request.RetryCount);
|
||||||
Assert.AreEqual(typeof(WebException), thrownException.GetType());
|
Assert.AreEqual(typeof(WebException), thrownException.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests being able to abort + restart a request.
|
/// Tests being able to abort + restart a request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestEventUnbindOnCompletion([Values(true, false)] bool async)
|
public void TestEventUnbindOnCompletion([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
var request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET };
|
||||||
|
|
||||||
request.Started += () => { };
|
request.Started += () => { };
|
||||||
request.Failed += e => { };
|
request.Failed += e => { };
|
||||||
request.DownloadProgress += (l1, l2) => { };
|
request.DownloadProgress += (l1, l2) => { };
|
||||||
request.UploadProgress += (l1, l2) => { };
|
request.UploadProgress += (l1, l2) => { };
|
||||||
|
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
var events = request.GetType().GetEvents(BindingFlags.Instance | BindingFlags.Public);
|
var events = request.GetType().GetEvents(BindingFlags.Instance | BindingFlags.Public);
|
||||||
foreach (var e in events)
|
foreach (var e in events)
|
||||||
{
|
{
|
||||||
var field = request.GetType().GetField(e.Name, BindingFlags.Instance | BindingFlags.Public);
|
var field = request.GetType().GetField(e.Name, BindingFlags.Instance | BindingFlags.Public);
|
||||||
Assert.IsFalse(((Delegate)field?.GetValue(request))?.GetInvocationList().Length > 0);
|
Assert.IsFalse(((Delegate)field?.GetValue(request))?.GetInvocationList().Length > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests being able to abort + restart a request.
|
/// Tests being able to abort + restart a request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestUnbindOnDispose([Values(true, false)] bool async)
|
public void TestUnbindOnDispose([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
WebRequest request;
|
WebRequest request;
|
||||||
using (request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET })
|
using (request = new JsonWebRequest<HttpBinGetResponse>("https://httpbin.org/get") { Method = HttpMethod.GET })
|
||||||
{
|
{
|
||||||
request.Started += () => { };
|
request.Started += () => { };
|
||||||
request.Failed += e => { };
|
request.Failed += e => { };
|
||||||
request.DownloadProgress += (l1, l2) => { };
|
request.DownloadProgress += (l1, l2) => { };
|
||||||
request.UploadProgress += (l1, l2) => { };
|
request.UploadProgress += (l1, l2) => { };
|
||||||
|
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
}
|
}
|
||||||
|
|
||||||
var events = request.GetType().GetEvents(BindingFlags.Instance | BindingFlags.Public);
|
var events = request.GetType().GetEvents(BindingFlags.Instance | BindingFlags.Public);
|
||||||
foreach (var e in events)
|
foreach (var e in events)
|
||||||
{
|
{
|
||||||
var field = request.GetType().GetField(e.Name, BindingFlags.Instance | BindingFlags.Public);
|
var field = request.GetType().GetField(e.Name, BindingFlags.Instance | BindingFlags.Public);
|
||||||
Assert.IsFalse(((Delegate)field?.GetValue(request))?.GetInvocationList().Length > 0);
|
Assert.IsFalse(((Delegate)field?.GetValue(request))?.GetInvocationList().Length > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestPostWithJsonResponse([Values(true, false)] bool async)
|
public void TestPostWithJsonResponse([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinPostResponse>("https://httpbin.org/post") { Method = HttpMethod.POST };
|
var request = new JsonWebRequest<HttpBinPostResponse>("https://httpbin.org/post") { Method = HttpMethod.POST };
|
||||||
|
|
||||||
request.AddParameter("testkey1", "testval1");
|
request.AddParameter("testkey1", "testval1");
|
||||||
request.AddParameter("testkey2", "testval2");
|
request.AddParameter("testkey2", "testval2");
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.DoesNotThrowAsync(request.PerformAsync);
|
Assert.DoesNotThrowAsync(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
var responseObject = request.ResponseObject;
|
var responseObject = request.ResponseObject;
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsFalse(request.Aborted);
|
Assert.IsFalse(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Form != null);
|
Assert.IsTrue(responseObject.Form != null);
|
||||||
Assert.IsTrue(responseObject.Form.Count == 2);
|
Assert.IsTrue(responseObject.Form.Count == 2);
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Headers.ContentLength > 0);
|
Assert.IsTrue(responseObject.Headers.ContentLength > 0);
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Form.ContainsKey("testkey1"));
|
Assert.IsTrue(responseObject.Form.ContainsKey("testkey1"));
|
||||||
Assert.IsTrue(responseObject.Form["testkey1"] == "testval1");
|
Assert.IsTrue(responseObject.Form["testkey1"] == "testval1");
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Form.ContainsKey("testkey2"));
|
Assert.IsTrue(responseObject.Form.ContainsKey("testkey2"));
|
||||||
Assert.IsTrue(responseObject.Form["testkey2"] == "testval2");
|
Assert.IsTrue(responseObject.Form["testkey2"] == "testval2");
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Headers.ContentType.StartsWith("multipart/form-data; boundary="));
|
Assert.IsTrue(responseObject.Headers.ContentType.StartsWith("multipart/form-data; boundary="));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestPostWithJsonRequest([Values(true, false)] bool async)
|
public void TestPostWithJsonRequest([Values(true, false)] bool async)
|
||||||
{
|
{
|
||||||
var request = new JsonWebRequest<HttpBinPostResponse>("https://httpbin.org/post") { Method = HttpMethod.POST };
|
var request = new JsonWebRequest<HttpBinPostResponse>("https://httpbin.org/post") { Method = HttpMethod.POST };
|
||||||
|
|
||||||
var testObject = new TestObject();
|
var testObject = new TestObject();
|
||||||
request.AddRaw(JsonConvert.SerializeObject(testObject));
|
request.AddRaw(JsonConvert.SerializeObject(testObject));
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.DoesNotThrowAsync(request.PerformAsync);
|
Assert.DoesNotThrowAsync(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
var responseObject = request.ResponseObject;
|
var responseObject = request.ResponseObject;
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsFalse(request.Aborted);
|
Assert.IsFalse(request.Aborted);
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Headers.ContentLength > 0);
|
Assert.IsTrue(responseObject.Headers.ContentLength > 0);
|
||||||
Assert.IsTrue(responseObject.Json != null);
|
Assert.IsTrue(responseObject.Json != null);
|
||||||
Assert.AreEqual(testObject.TestString, responseObject.Json.TestString);
|
Assert.AreEqual(testObject.TestString, responseObject.Json.TestString);
|
||||||
|
|
||||||
Assert.IsTrue(responseObject.Headers.ContentType == null);
|
Assert.IsTrue(responseObject.Headers.ContentType == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test, Retry(5)]
|
[Test, Retry(5)]
|
||||||
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
[Ignore("Broken (appveyor or httpbin.org, see https://ci.appveyor.com/project/peppy/osu-framework/build/5155)")]
|
||||||
public void TestGetBinaryData([Values(true, false)] bool async, [Values(true, false)] bool chunked)
|
public void TestGetBinaryData([Values(true, false)] bool async, [Values(true, false)] bool chunked)
|
||||||
{
|
{
|
||||||
const int bytes_count = 65536;
|
const int bytes_count = 65536;
|
||||||
const int chunk_size = 1024;
|
const int chunk_size = 1024;
|
||||||
|
|
||||||
string endpoint = chunked ? "stream-bytes" : "bytes";
|
string endpoint = chunked ? "stream-bytes" : "bytes";
|
||||||
|
|
||||||
WebRequest request = new WebRequest($"http://httpbin.org/{endpoint}/{bytes_count}") { Method = HttpMethod.GET };
|
WebRequest request = new WebRequest($"http://httpbin.org/{endpoint}/{bytes_count}") { Method = HttpMethod.GET };
|
||||||
if (chunked)
|
if (chunked)
|
||||||
request.AddParameter("chunk_size", chunk_size.ToString());
|
request.AddParameter("chunk_size", chunk_size.ToString());
|
||||||
|
|
||||||
if (async)
|
if (async)
|
||||||
Assert.DoesNotThrowAsync(request.PerformAsync);
|
Assert.DoesNotThrowAsync(request.PerformAsync);
|
||||||
else
|
else
|
||||||
Assert.DoesNotThrow(request.Perform);
|
Assert.DoesNotThrow(request.Perform);
|
||||||
|
|
||||||
Assert.IsTrue(request.Completed);
|
Assert.IsTrue(request.Completed);
|
||||||
Assert.IsFalse(request.Aborted);
|
Assert.IsFalse(request.Aborted);
|
||||||
|
|
||||||
Assert.AreEqual(bytes_count, request.ResponseStream.Length);
|
Assert.AreEqual(bytes_count, request.ResponseStream.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
private class HttpBinGetResponse
|
private class HttpBinGetResponse
|
||||||
{
|
{
|
||||||
[JsonProperty("headers")]
|
[JsonProperty("headers")]
|
||||||
public HttpBinHeaders Headers { get; set; }
|
public HttpBinHeaders Headers { get; set; }
|
||||||
|
|
||||||
[JsonProperty("url")]
|
[JsonProperty("url")]
|
||||||
public string Url { get; set; }
|
public string Url { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
private class HttpBinPostResponse
|
private class HttpBinPostResponse
|
||||||
{
|
{
|
||||||
[JsonProperty("data")]
|
[JsonProperty("data")]
|
||||||
public string Data { get; set; }
|
public string Data { get; set; }
|
||||||
|
|
||||||
[JsonProperty("form")]
|
[JsonProperty("form")]
|
||||||
public IDictionary<string, string> Form { get; set; }
|
public IDictionary<string, string> Form { get; set; }
|
||||||
|
|
||||||
[JsonProperty("headers")]
|
[JsonProperty("headers")]
|
||||||
public HttpBinHeaders Headers { get; set; }
|
public HttpBinHeaders Headers { get; set; }
|
||||||
|
|
||||||
[JsonProperty("json")]
|
[JsonProperty("json")]
|
||||||
public TestObject Json { get; set; }
|
public TestObject Json { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class HttpBinHeaders
|
public class HttpBinHeaders
|
||||||
{
|
{
|
||||||
[JsonProperty("Content-Length")]
|
[JsonProperty("Content-Length")]
|
||||||
public int ContentLength { get; set; }
|
public int ContentLength { get; set; }
|
||||||
|
|
||||||
[JsonProperty("Content-Type")]
|
[JsonProperty("Content-Type")]
|
||||||
public string ContentType { get; set; }
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
[JsonProperty("User-Agent")]
|
[JsonProperty("User-Agent")]
|
||||||
public string UserAgent { get; set; }
|
public string UserAgent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class TestObject
|
public class TestObject
|
||||||
{
|
{
|
||||||
public string TestString = "readable";
|
public string TestString = "readable";
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DelayedWebRequest : WebRequest
|
private class DelayedWebRequest : WebRequest
|
||||||
{
|
{
|
||||||
public Action CompleteInvoked;
|
public Action CompleteInvoked;
|
||||||
|
|
||||||
private int delay;
|
private int delay;
|
||||||
|
|
||||||
public int Delay
|
public int Delay
|
||||||
{
|
{
|
||||||
get { return delay; }
|
get { return delay; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
delay = value;
|
delay = value;
|
||||||
Url = $"http://httpbin.org/delay/{delay}";
|
Url = $"http://httpbin.org/delay/{delay}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DelayedWebRequest()
|
public DelayedWebRequest()
|
||||||
: base("http://httpbin.org/delay/0")
|
: base("http://httpbin.org/delay/0")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Complete(Exception e = null)
|
protected override void Complete(Exception e = null)
|
||||||
{
|
{
|
||||||
CompleteInvoked?.Invoke();
|
CompleteInvoked?.Invoke();
|
||||||
base.Complete(e);
|
base.Complete(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +1,140 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Lists
|
namespace osu.Framework.Tests.Lists
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestArrayExtensions
|
public class TestArrayExtensions
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNullToJagged()
|
public void TestNullToJagged()
|
||||||
{
|
{
|
||||||
int[][] result = null;
|
int[][] result = null;
|
||||||
Assert.DoesNotThrow(() => result = ((int[,])null).ToJagged());
|
Assert.DoesNotThrow(() => result = ((int[,])null).ToJagged());
|
||||||
Assert.AreEqual(null, result);
|
Assert.AreEqual(null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNullToRectangular()
|
public void TestNullToRectangular()
|
||||||
{
|
{
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = ((int[][])null).ToRectangular());
|
Assert.DoesNotThrow(() => result = ((int[][])null).ToRectangular());
|
||||||
Assert.AreEqual(null, result);
|
Assert.AreEqual(null, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEmptyRectangularToJagged()
|
public void TestEmptyRectangularToJagged()
|
||||||
{
|
{
|
||||||
int[][] result = null;
|
int[][] result = null;
|
||||||
Assert.DoesNotThrow(() => result = new int[0, 0].ToJagged());
|
Assert.DoesNotThrow(() => result = new int[0, 0].ToJagged());
|
||||||
Assert.AreEqual(0, result.Length);
|
Assert.AreEqual(0, result.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestEmptyJaggedToRectangular()
|
public void TestEmptyJaggedToRectangular()
|
||||||
{
|
{
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = new int[0][].ToRectangular());
|
Assert.DoesNotThrow(() => result = new int[0][].ToRectangular());
|
||||||
Assert.AreEqual(0, result.Length);
|
Assert.AreEqual(0, result.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRectangularColumnToJagged()
|
public void TestRectangularColumnToJagged()
|
||||||
{
|
{
|
||||||
int[][] result = null;
|
int[][] result = null;
|
||||||
Assert.DoesNotThrow(() => result = new int[1, 10].ToJagged());
|
Assert.DoesNotThrow(() => result = new int[1, 10].ToJagged());
|
||||||
Assert.AreEqual(1, result.Length);
|
Assert.AreEqual(1, result.Length);
|
||||||
Assert.AreEqual(10, result[0].Length);
|
Assert.AreEqual(10, result[0].Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJaggedColumnToRectangular()
|
public void TestJaggedColumnToRectangular()
|
||||||
{
|
{
|
||||||
var jagged = new int[10][];
|
var jagged = new int[10][];
|
||||||
|
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
||||||
Assert.AreEqual(10, result.GetLength(0));
|
Assert.AreEqual(10, result.GetLength(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRectangularRowToJagged()
|
public void TestRectangularRowToJagged()
|
||||||
{
|
{
|
||||||
int[][] result = null;
|
int[][] result = null;
|
||||||
Assert.DoesNotThrow(() => result = new int[10, 0].ToJagged());
|
Assert.DoesNotThrow(() => result = new int[10, 0].ToJagged());
|
||||||
Assert.AreEqual(10, result.Length);
|
Assert.AreEqual(10, result.Length);
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
Assert.AreEqual(0, result[i].Length);
|
Assert.AreEqual(0, result[i].Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJaggedRowToRectangular()
|
public void TestJaggedRowToRectangular()
|
||||||
{
|
{
|
||||||
var jagged = new int[1][];
|
var jagged = new int[1][];
|
||||||
jagged[0] = new int[10];
|
jagged[0] = new int[10];
|
||||||
|
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
||||||
Assert.AreEqual(10, result.GetLength(1));
|
Assert.AreEqual(10, result.GetLength(1));
|
||||||
Assert.AreEqual(1, result.GetLength(0));
|
Assert.AreEqual(1, result.GetLength(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSquareRectangularToJagged()
|
public void TestSquareRectangularToJagged()
|
||||||
{
|
{
|
||||||
int[][] result = null;
|
int[][] result = null;
|
||||||
Assert.DoesNotThrow(() => result = new int[10, 10].ToJagged());
|
Assert.DoesNotThrow(() => result = new int[10, 10].ToJagged());
|
||||||
Assert.AreEqual(10, result.Length);
|
Assert.AreEqual(10, result.Length);
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
Assert.AreEqual(10, result[i].Length);
|
Assert.AreEqual(10, result[i].Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSquareJaggedToRectangular()
|
public void TestSquareJaggedToRectangular()
|
||||||
{
|
{
|
||||||
var jagged = new int[10][];
|
var jagged = new int[10][];
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
jagged[i] = new int[10];
|
jagged[i] = new int[10];
|
||||||
|
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
||||||
Assert.AreEqual(10, result.GetLength(0));
|
Assert.AreEqual(10, result.GetLength(0));
|
||||||
Assert.AreEqual(10, result.GetLength(1));
|
Assert.AreEqual(10, result.GetLength(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNonSquareJaggedToRectangular()
|
public void TestNonSquareJaggedToRectangular()
|
||||||
{
|
{
|
||||||
var jagged = new int[10][];
|
var jagged = new int[10][];
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
jagged[i] = new int[i];
|
jagged[i] = new int[i];
|
||||||
|
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
||||||
Assert.AreEqual(10, result.GetLength(0));
|
Assert.AreEqual(10, result.GetLength(0));
|
||||||
Assert.AreEqual(9, result.GetLength(1));
|
Assert.AreEqual(9, result.GetLength(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestNonSquareJaggedWithNullRowsToRectangular()
|
public void TestNonSquareJaggedWithNullRowsToRectangular()
|
||||||
{
|
{
|
||||||
var jagged = new int[10][];
|
var jagged = new int[10][];
|
||||||
for (int i = 1; i < 10; i += 2)
|
for (int i = 1; i < 10; i += 2)
|
||||||
{
|
{
|
||||||
if (i % 2 == 1)
|
if (i % 2 == 1)
|
||||||
jagged[i] = new int[i];
|
jagged[i] = new int[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
int[,] result = null;
|
int[,] result = null;
|
||||||
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
Assert.DoesNotThrow(() => result = jagged.ToRectangular());
|
||||||
Assert.AreEqual(10, result.GetLength(0));
|
Assert.AreEqual(10, result.GetLength(0));
|
||||||
Assert.AreEqual(9, result.GetLength(1));
|
Assert.AreEqual(9, result.GetLength(1));
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
Assert.AreEqual(0, result[i, 0]);
|
Assert.AreEqual(0, result[i, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,88 +1,88 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Lists;
|
using osu.Framework.Lists;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Lists
|
namespace osu.Framework.Tests.Lists
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSortedList
|
public class TestSortedList
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAdd()
|
public void TestAdd()
|
||||||
{
|
{
|
||||||
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
||||||
{
|
{
|
||||||
10,
|
10,
|
||||||
8,
|
8,
|
||||||
13,
|
13,
|
||||||
-10
|
-10
|
||||||
};
|
};
|
||||||
Assert.AreEqual(-10, list[0]);
|
Assert.AreEqual(-10, list[0]);
|
||||||
Assert.AreEqual(8, list[1]);
|
Assert.AreEqual(8, list[1]);
|
||||||
Assert.AreEqual(10, list[2]);
|
Assert.AreEqual(10, list[2]);
|
||||||
Assert.AreEqual(13, list[3]);
|
Assert.AreEqual(13, list[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRemove()
|
public void TestRemove()
|
||||||
{
|
{
|
||||||
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
||||||
{
|
{
|
||||||
10,
|
10,
|
||||||
8,
|
8,
|
||||||
13,
|
13,
|
||||||
-10
|
-10
|
||||||
};
|
};
|
||||||
list.Remove(8);
|
list.Remove(8);
|
||||||
Assert.IsFalse(list.Any(i => i == 8));
|
Assert.IsFalse(list.Any(i => i == 8));
|
||||||
Assert.AreEqual(3, list.Count);
|
Assert.AreEqual(3, list.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestRemoveAt()
|
public void TestRemoveAt()
|
||||||
{
|
{
|
||||||
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
||||||
{
|
{
|
||||||
10,
|
10,
|
||||||
8,
|
8,
|
||||||
13,
|
13,
|
||||||
-10
|
-10
|
||||||
};
|
};
|
||||||
list.RemoveAt(0);
|
list.RemoveAt(0);
|
||||||
Assert.IsFalse(list.Any(i => i == -10));
|
Assert.IsFalse(list.Any(i => i == -10));
|
||||||
Assert.AreEqual(3, list.Count);
|
Assert.AreEqual(3, list.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestClear()
|
public void TestClear()
|
||||||
{
|
{
|
||||||
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
var list = new SortedList<int>(Comparer<int>.Create((a, b) => a - b))
|
||||||
{
|
{
|
||||||
10,
|
10,
|
||||||
8,
|
8,
|
||||||
13,
|
13,
|
||||||
-10
|
-10
|
||||||
};
|
};
|
||||||
list.Clear();
|
list.Clear();
|
||||||
Assert.IsFalse(list.Any());
|
Assert.IsFalse(list.Any());
|
||||||
Assert.AreEqual(0, list.Count);
|
Assert.AreEqual(0, list.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestIndexOf()
|
public void TestIndexOf()
|
||||||
{
|
{
|
||||||
var list = new SortedList<int>(Comparer<int>.Default)
|
var list = new SortedList<int>(Comparer<int>.Default)
|
||||||
{
|
{
|
||||||
10,
|
10,
|
||||||
10,
|
10,
|
||||||
10,
|
10,
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.IsTrue(list.IndexOf(10) >= 0);
|
Assert.IsTrue(list.IndexOf(10) >= 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.MathUtils
|
namespace osu.Framework.Tests.MathUtils
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestInterpolation
|
public class TestInterpolation
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestLerp()
|
public void TestLerp()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(5, Interpolation.Lerp(0, 10, 0.5f));
|
Assert.AreEqual(5, Interpolation.Lerp(0, 10, 0.5f));
|
||||||
Assert.AreEqual(0, Interpolation.Lerp(0, 10, 0));
|
Assert.AreEqual(0, Interpolation.Lerp(0, 10, 0));
|
||||||
Assert.AreEqual(10, Interpolation.Lerp(0, 10, 1));
|
Assert.AreEqual(10, Interpolation.Lerp(0, 10, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +1,51 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Platform
|
namespace osu.Framework.Tests.Platform
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class HeadlessGameHostTest
|
public class HeadlessGameHostTest
|
||||||
{
|
{
|
||||||
private class Foobar
|
private class Foobar
|
||||||
{
|
{
|
||||||
public string Bar;
|
public string Bar;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestIpc()
|
public void TestIpc()
|
||||||
{
|
{
|
||||||
using (var server = new HeadlessGameHost(@"server", true))
|
using (var server = new HeadlessGameHost(@"server", true))
|
||||||
using (var client = new HeadlessGameHost(@"client", true))
|
using (var client = new HeadlessGameHost(@"client", true))
|
||||||
{
|
{
|
||||||
Assert.IsTrue(server.IsPrimaryInstance, @"Server wasn't able to bind");
|
Assert.IsTrue(server.IsPrimaryInstance, @"Server wasn't able to bind");
|
||||||
Assert.IsFalse(client.IsPrimaryInstance, @"Client was able to bind when it shouldn't have been able to");
|
Assert.IsFalse(client.IsPrimaryInstance, @"Client was able to bind when it shouldn't have been able to");
|
||||||
|
|
||||||
var serverChannel = new IpcChannel<Foobar>(server);
|
var serverChannel = new IpcChannel<Foobar>(server);
|
||||||
var clientChannel = new IpcChannel<Foobar>(client);
|
var clientChannel = new IpcChannel<Foobar>(client);
|
||||||
|
|
||||||
Action waitAction = () =>
|
Action waitAction = () =>
|
||||||
{
|
{
|
||||||
bool received = false;
|
bool received = false;
|
||||||
serverChannel.MessageReceived += message =>
|
serverChannel.MessageReceived += message =>
|
||||||
{
|
{
|
||||||
Assert.AreEqual("example", message.Bar);
|
Assert.AreEqual("example", message.Bar);
|
||||||
received = true;
|
received = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
clientChannel.SendMessageAsync(new Foobar { Bar = "example" }).Wait();
|
clientChannel.SendMessageAsync(new Foobar { Bar = "example" }).Wait();
|
||||||
|
|
||||||
while (!received)
|
while (!received)
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(10000),
|
Assert.IsTrue(waitAction.BeginInvoke(null, null).AsyncWaitHandle.WaitOne(10000),
|
||||||
@"Message was not received in a timely fashion");
|
@"Message was not received in a timely fashion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
|
|
||||||
namespace osu.Framework.Tests
|
namespace osu.Framework.Tests
|
||||||
{
|
{
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
bool benchmark = args.Length > 0 && args[0] == @"-benchmark";
|
bool benchmark = args.Length > 0 && args[0] == @"-benchmark";
|
||||||
|
|
||||||
using (GameHost host = Host.GetSuitableHost(@"visual-tests"))
|
using (GameHost host = Host.GetSuitableHost(@"visual-tests"))
|
||||||
{
|
{
|
||||||
if (benchmark)
|
if (benchmark)
|
||||||
host.Run(new AutomatedVisualTestGame());
|
host.Run(new AutomatedVisualTestGame());
|
||||||
else
|
else
|
||||||
host.Run(new VisualTestGame());
|
host.Run(new VisualTestGame());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
|
||||||
namespace osu.Framework.Tests
|
namespace osu.Framework.Tests
|
||||||
{
|
{
|
||||||
internal class TestGame : Game
|
internal class TestGame : Game
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Resources.AddStore(new NamespacedResourceStore<byte[]>(new DllResourceStore(Assembly.GetExecutingAssembly().Location), "Resources"));
|
Resources.AddStore(new NamespacedResourceStore<byte[]>(new DllResourceStore(Assembly.GetExecutingAssembly().Location), "Resources"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public abstract class FrameworkTestCase : TestCase
|
public abstract class FrameworkTestCase : TestCase
|
||||||
{
|
{
|
||||||
public override void RunTest()
|
public override void RunTest()
|
||||||
{
|
{
|
||||||
using (var host = new HeadlessGameHost())
|
using (var host = new HeadlessGameHost())
|
||||||
host.Run(new FrameworkTestCaseTestRunner(this));
|
host.Run(new FrameworkTestCaseTestRunner(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FrameworkTestCaseTestRunner : TestCaseTestRunner
|
private class FrameworkTestCaseTestRunner : TestCaseTestRunner
|
||||||
{
|
{
|
||||||
public FrameworkTestCaseTestRunner(TestCase testCase)
|
public FrameworkTestCaseTestRunner(TestCase testCase)
|
||||||
: base(testCase)
|
: base(testCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Resources.AddStore(new NamespacedResourceStore<byte[]>(new DllResourceStore(@"osu.Framework.Tests.exe"), "Resources"));
|
Resources.AddStore(new NamespacedResourceStore<byte[]>(new DllResourceStore(@"osu.Framework.Tests.exe"), "Resources"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,65 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Animations;
|
using osu.Framework.Graphics.Animations;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("frame-based animations")]
|
[System.ComponentModel.Description("frame-based animations")]
|
||||||
public class TestCaseAnimation : TestCase
|
public class TestCaseAnimation : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseAnimation()
|
public TestCaseAnimation()
|
||||||
{
|
{
|
||||||
DrawableAnimation drawableAnimation;
|
DrawableAnimation drawableAnimation;
|
||||||
|
|
||||||
Add(new Container
|
Add(new Container
|
||||||
{
|
{
|
||||||
Position = new Vector2(10f, 10f),
|
Position = new Vector2(10f, 10f),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new DelayedLoadWrapper(new AvatarAnimation
|
new DelayedLoadWrapper(new AvatarAnimation
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.None,
|
AutoSizeAxes = Axes.None,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.25f)
|
Size = new Vector2(0.25f)
|
||||||
}),
|
}),
|
||||||
drawableAnimation = new DrawableAnimation
|
drawableAnimation = new DrawableAnimation
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
Position = new Vector2(0f, 0.3f),
|
Position = new Vector2(0f, 0.3f),
|
||||||
AutoSizeAxes = Axes.None,
|
AutoSizeAxes = Axes.None,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.25f)
|
Size = new Vector2(0.25f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
drawableAnimation.AddFrames(new[]
|
drawableAnimation.AddFrames(new[]
|
||||||
{
|
{
|
||||||
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Red }, 500),
|
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Red }, 500),
|
||||||
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Green }, 500),
|
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Green }, 500),
|
||||||
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Blue }, 500),
|
new FrameData<Drawable>(new Box { Size = new Vector2(50f), Colour = Color4.Blue }, 500),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AvatarAnimation : TextureAnimation
|
private class AvatarAnimation : TextureAnimation
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(TextureStore textures)
|
||||||
{
|
{
|
||||||
AddFrame(textures.Get("https://a.ppy.sh/2"), 500);
|
AddFrame(textures.Get("https://a.ppy.sh/2"), 500);
|
||||||
AddFrame(textures.Get("https://a.ppy.sh/3"), 500);
|
AddFrame(textures.Get("https://a.ppy.sh/3"), 500);
|
||||||
AddFrame(textures.Get("https://a.ppy.sh/1876669"), 500);
|
AddFrame(textures.Get("https://a.ppy.sh/1876669"), 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,232 +1,232 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseBindableNumbers : TestCase
|
public class TestCaseBindableNumbers : TestCase
|
||||||
{
|
{
|
||||||
private readonly BindableInt bindableInt = new BindableInt();
|
private readonly BindableInt bindableInt = new BindableInt();
|
||||||
private readonly BindableLong bindableLong = new BindableLong();
|
private readonly BindableLong bindableLong = new BindableLong();
|
||||||
private readonly BindableDouble bindableDouble = new BindableDouble();
|
private readonly BindableDouble bindableDouble = new BindableDouble();
|
||||||
private readonly BindableFloat bindableFloat = new BindableFloat();
|
private readonly BindableFloat bindableFloat = new BindableFloat();
|
||||||
|
|
||||||
public TestCaseBindableNumbers()
|
public TestCaseBindableNumbers()
|
||||||
{
|
{
|
||||||
AddStep("Reset", () =>
|
AddStep("Reset", () =>
|
||||||
{
|
{
|
||||||
setValue(0);
|
setValue(0);
|
||||||
setPrecision(1);
|
setPrecision(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
testBasic();
|
testBasic();
|
||||||
testPrecision3();
|
testPrecision3();
|
||||||
testPrecision10();
|
testPrecision10();
|
||||||
testMinMaxWithoutPrecision();
|
testMinMaxWithoutPrecision();
|
||||||
testMinMaxWithPrecision();
|
testMinMaxWithPrecision();
|
||||||
testInvalidPrecision();
|
testInvalidPrecision();
|
||||||
testFractionalPrecision();
|
testFractionalPrecision();
|
||||||
|
|
||||||
AddSliderStep("Min value", -100, 100, -100, setMin);
|
AddSliderStep("Min value", -100, 100, -100, setMin);
|
||||||
AddSliderStep("Max value", -100, 100, 100, setMax);
|
AddSliderStep("Max value", -100, 100, 100, setMax);
|
||||||
AddSliderStep("Value", -100, 100, 0, setValue);
|
AddSliderStep("Value", -100, 100, 0, setValue);
|
||||||
AddSliderStep("Precision", 1, 10, 1, setPrecision);
|
AddSliderStep("Precision", 1, 10, 1, setPrecision);
|
||||||
|
|
||||||
Child = new GridContainer
|
Child = new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new BindableDisplayContainer<int>(bindableInt),
|
new BindableDisplayContainer<int>(bindableInt),
|
||||||
new BindableDisplayContainer<long>(bindableLong),
|
new BindableDisplayContainer<long>(bindableLong),
|
||||||
},
|
},
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new BindableDisplayContainer<float>(bindableFloat),
|
new BindableDisplayContainer<float>(bindableFloat),
|
||||||
new BindableDisplayContainer<double>(bindableDouble),
|
new BindableDisplayContainer<double>(bindableDouble),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests basic setting of values.
|
/// Tests basic setting of values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testBasic()
|
private void testBasic()
|
||||||
{
|
{
|
||||||
AddStep("Value = 10", () => setValue(10));
|
AddStep("Value = 10", () => setValue(10));
|
||||||
AddAssert("Check = 10", () => checkExact(10));
|
AddAssert("Check = 10", () => checkExact(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that midpoint values are correctly rounded with a precision of 3.
|
/// Tests that midpoint values are correctly rounded with a precision of 3.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testPrecision3()
|
private void testPrecision3()
|
||||||
{
|
{
|
||||||
AddStep("Precision = 3", () => setPrecision(3));
|
AddStep("Precision = 3", () => setPrecision(3));
|
||||||
AddStep("Value = 4", () => setValue(3));
|
AddStep("Value = 4", () => setValue(3));
|
||||||
AddAssert("Check = 3", () => checkExact(3));
|
AddAssert("Check = 3", () => checkExact(3));
|
||||||
AddStep("Value = 5", () => setValue(5));
|
AddStep("Value = 5", () => setValue(5));
|
||||||
AddAssert("Check = 6", () => checkExact(6));
|
AddAssert("Check = 6", () => checkExact(6));
|
||||||
AddStep("Value = 59", () => setValue(59));
|
AddStep("Value = 59", () => setValue(59));
|
||||||
AddAssert("Check = 60", () => checkExact(60));
|
AddAssert("Check = 60", () => checkExact(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that midpoint values are correctly rounded with a precision of 10.
|
/// Tests that midpoint values are correctly rounded with a precision of 10.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testPrecision10()
|
private void testPrecision10()
|
||||||
{
|
{
|
||||||
AddStep("Precision = 10", () => setPrecision(10));
|
AddStep("Precision = 10", () => setPrecision(10));
|
||||||
AddStep("Value = 6", () => setValue(6));
|
AddStep("Value = 6", () => setValue(6));
|
||||||
AddAssert("Check = 10", () => checkExact(10));
|
AddAssert("Check = 10", () => checkExact(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that values are correctly clamped to min/max values.
|
/// Tests that values are correctly clamped to min/max values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testMinMaxWithoutPrecision()
|
private void testMinMaxWithoutPrecision()
|
||||||
{
|
{
|
||||||
AddStep("Precision = 1", () => setPrecision(1));
|
AddStep("Precision = 1", () => setPrecision(1));
|
||||||
AddStep("Min = -30", () => setMin(-30));
|
AddStep("Min = -30", () => setMin(-30));
|
||||||
AddStep("Max = 30", () => setMax(30));
|
AddStep("Max = 30", () => setMax(30));
|
||||||
AddStep("Value = -50", () => setValue(-50));
|
AddStep("Value = -50", () => setValue(-50));
|
||||||
AddAssert("Check = -30", () => checkExact(-30));
|
AddAssert("Check = -30", () => checkExact(-30));
|
||||||
AddStep("Value = 50", () => setValue(50));
|
AddStep("Value = 50", () => setValue(50));
|
||||||
AddAssert("Check = 30", () => checkExact(30));
|
AddAssert("Check = 30", () => checkExact(30));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that values are correctly clamped to min/max values when precision is involved.
|
/// Tests that values are correctly clamped to min/max values when precision is involved.
|
||||||
/// In this case, precision is preferred over min/max values.
|
/// In this case, precision is preferred over min/max values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testMinMaxWithPrecision()
|
private void testMinMaxWithPrecision()
|
||||||
{
|
{
|
||||||
AddStep("Precision = 5", () => setPrecision(5));
|
AddStep("Precision = 5", () => setPrecision(5));
|
||||||
AddStep("Min = -27", () => setMin(-27));
|
AddStep("Min = -27", () => setMin(-27));
|
||||||
AddStep("Max = 27", () => setMax(27));
|
AddStep("Max = 27", () => setMax(27));
|
||||||
AddStep("Value = -30", () => setValue(-30));
|
AddStep("Value = -30", () => setValue(-30));
|
||||||
AddAssert("Check = -25", () => checkExact(-25));
|
AddAssert("Check = -25", () => checkExact(-25));
|
||||||
AddStep("Value = 30", () => setValue(30));
|
AddStep("Value = 30", () => setValue(30));
|
||||||
AddAssert("Check = 25", () => checkExact(25));
|
AddAssert("Check = 25", () => checkExact(25));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that invalid precisions cause exceptions.
|
/// Tests that invalid precisions cause exceptions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testInvalidPrecision()
|
private void testInvalidPrecision()
|
||||||
{
|
{
|
||||||
AddAssert("Precision = 0 throws", () =>
|
AddAssert("Precision = 0 throws", () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setPrecision(0);
|
setPrecision(0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Precision = -1 throws", () =>
|
AddAssert("Precision = -1 throws", () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setPrecision(-1);
|
setPrecision(-1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that fractional precisions are obeyed.
|
/// Tests that fractional precisions are obeyed.
|
||||||
/// Note that int bindables are assigned int precisions/values, so their results will differ.
|
/// Note that int bindables are assigned int precisions/values, so their results will differ.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testFractionalPrecision()
|
private void testFractionalPrecision()
|
||||||
{
|
{
|
||||||
AddStep("Precision = 2.25/2", () => setPrecision(2.25));
|
AddStep("Precision = 2.25/2", () => setPrecision(2.25));
|
||||||
AddStep("Value = 3.3/3", () => setValue(3.3));
|
AddStep("Value = 3.3/3", () => setValue(3.3));
|
||||||
AddAssert("Check = 2.25/4", () => checkExact(2.25m, 4));
|
AddAssert("Check = 2.25/4", () => checkExact(2.25m, 4));
|
||||||
AddStep("Value = 4.17/4", () => setValue(4.17));
|
AddStep("Value = 4.17/4", () => setValue(4.17));
|
||||||
AddAssert("Check = 4.5/4", () => checkExact(4.5m, 4));
|
AddAssert("Check = 4.5/4", () => checkExact(4.5m, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool checkExact(decimal value) => checkExact(value, value);
|
private bool checkExact(decimal value) => checkExact(value, value);
|
||||||
|
|
||||||
private bool checkExact(decimal floatValue, decimal intValue)
|
private bool checkExact(decimal floatValue, decimal intValue)
|
||||||
=> bindableInt.Value == Convert.ToInt32(intValue)
|
=> bindableInt.Value == Convert.ToInt32(intValue)
|
||||||
&& bindableLong.Value == Convert.ToInt64(intValue)
|
&& bindableLong.Value == Convert.ToInt64(intValue)
|
||||||
&& bindableFloat.Value == Convert.ToSingle(floatValue)
|
&& bindableFloat.Value == Convert.ToSingle(floatValue)
|
||||||
&& bindableDouble.Value == Convert.ToDouble(floatValue);
|
&& bindableDouble.Value == Convert.ToDouble(floatValue);
|
||||||
|
|
||||||
private void setMin<T>(T value)
|
private void setMin<T>(T value)
|
||||||
{
|
{
|
||||||
bindableInt.MinValue = Convert.ToInt32(value);
|
bindableInt.MinValue = Convert.ToInt32(value);
|
||||||
bindableLong.MinValue = Convert.ToInt64(value);
|
bindableLong.MinValue = Convert.ToInt64(value);
|
||||||
bindableFloat.MinValue = Convert.ToSingle(value);
|
bindableFloat.MinValue = Convert.ToSingle(value);
|
||||||
bindableDouble.MinValue = Convert.ToDouble(value);
|
bindableDouble.MinValue = Convert.ToDouble(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setMax<T>(T value)
|
private void setMax<T>(T value)
|
||||||
{
|
{
|
||||||
bindableInt.MaxValue = Convert.ToInt32(value);
|
bindableInt.MaxValue = Convert.ToInt32(value);
|
||||||
bindableLong.MaxValue = Convert.ToInt64(value);
|
bindableLong.MaxValue = Convert.ToInt64(value);
|
||||||
bindableFloat.MaxValue = Convert.ToSingle(value);
|
bindableFloat.MaxValue = Convert.ToSingle(value);
|
||||||
bindableDouble.MaxValue = Convert.ToDouble(value);
|
bindableDouble.MaxValue = Convert.ToDouble(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setValue<T>(T value)
|
private void setValue<T>(T value)
|
||||||
{
|
{
|
||||||
bindableInt.Value = Convert.ToInt32(value);
|
bindableInt.Value = Convert.ToInt32(value);
|
||||||
bindableLong.Value = Convert.ToInt64(value);
|
bindableLong.Value = Convert.ToInt64(value);
|
||||||
bindableFloat.Value = Convert.ToSingle(value);
|
bindableFloat.Value = Convert.ToSingle(value);
|
||||||
bindableDouble.Value = Convert.ToDouble(value);
|
bindableDouble.Value = Convert.ToDouble(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPrecision<T>(T precision)
|
private void setPrecision<T>(T precision)
|
||||||
{
|
{
|
||||||
bindableInt.Precision = Convert.ToInt32(precision);
|
bindableInt.Precision = Convert.ToInt32(precision);
|
||||||
bindableLong.Precision = Convert.ToInt64(precision);
|
bindableLong.Precision = Convert.ToInt64(precision);
|
||||||
bindableFloat.Precision = Convert.ToSingle(precision);
|
bindableFloat.Precision = Convert.ToSingle(precision);
|
||||||
bindableDouble.Precision = Convert.ToDouble(precision);
|
bindableDouble.Precision = Convert.ToDouble(precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BindableDisplayContainer<T> : CompositeDrawable
|
private class BindableDisplayContainer<T> : CompositeDrawable
|
||||||
where T : struct, IComparable, IConvertible
|
where T : struct, IComparable, IConvertible
|
||||||
{
|
{
|
||||||
public BindableDisplayContainer(BindableNumber<T> bindable)
|
public BindableDisplayContainer(BindableNumber<T> bindable)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
SpriteText valueText;
|
SpriteText valueText;
|
||||||
InternalChild = new FillFlowContainer
|
InternalChild = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = $"{typeof(T).Name} value:" },
|
new SpriteText { Text = $"{typeof(T).Name} value:" },
|
||||||
valueText = new SpriteText { Text = bindable.Value.ToString(CultureInfo.InvariantCulture) }
|
valueText = new SpriteText { Text = bindable.Value.ToString(CultureInfo.InvariantCulture) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bindable.ValueChanged += v => valueText.Text = v.ToString(CultureInfo.InvariantCulture);
|
bindable.ValueChanged += v => valueText.Text = v.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,177 +1,177 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseBlending : TestCase
|
public class TestCaseBlending : TestCase
|
||||||
{
|
{
|
||||||
private readonly Dropdown<BlendingMode> colourModeDropdown;
|
private readonly Dropdown<BlendingMode> colourModeDropdown;
|
||||||
private readonly Dropdown<BlendingEquation> colourEquation;
|
private readonly Dropdown<BlendingEquation> colourEquation;
|
||||||
private readonly Dropdown<BlendingEquation> alphaEquation;
|
private readonly Dropdown<BlendingEquation> alphaEquation;
|
||||||
private readonly BufferedContainer foregroundContainer;
|
private readonly BufferedContainer foregroundContainer;
|
||||||
|
|
||||||
public TestCaseBlending()
|
public TestCaseBlending()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Name = "Settings",
|
Name = "Settings",
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Y = 50,
|
Y = 50,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 20),
|
Spacing = new Vector2(0, 20),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 5),
|
Spacing = new Vector2(0, 5),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = "Blending mode" },
|
new SpriteText { Text = "Blending mode" },
|
||||||
colourModeDropdown = new BasicDropdown<BlendingMode> { Width = 200 }
|
colourModeDropdown = new BasicDropdown<BlendingMode> { Width = 200 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 5),
|
Spacing = new Vector2(0, 5),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = "Blending equation (colour)" },
|
new SpriteText { Text = "Blending equation (colour)" },
|
||||||
colourEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
|
colourEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 5),
|
Spacing = new Vector2(0, 5),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = "Blending equation (alpha)" },
|
new SpriteText { Text = "Blending equation (alpha)" },
|
||||||
alphaEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
|
alphaEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Behind background"
|
Text = "Behind background"
|
||||||
},
|
},
|
||||||
new BufferedContainer
|
new BufferedContainer
|
||||||
{
|
{
|
||||||
Name = "Background",
|
Name = "Background",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fit,
|
FillMode = FillMode.Fit,
|
||||||
Size = new Vector2(0.85f),
|
Size = new Vector2(0.85f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new GradientPart(0, Color4.Orange, Color4.Yellow),
|
new GradientPart(0, Color4.Orange, Color4.Yellow),
|
||||||
new GradientPart(1, Color4.Yellow, Color4.Green),
|
new GradientPart(1, Color4.Yellow, Color4.Green),
|
||||||
new GradientPart(2, Color4.Green, Color4.Cyan),
|
new GradientPart(2, Color4.Green, Color4.Cyan),
|
||||||
new GradientPart(3, Color4.Cyan, Color4.Blue),
|
new GradientPart(3, Color4.Cyan, Color4.Blue),
|
||||||
new GradientPart(4, Color4.Blue, Color4.Violet),
|
new GradientPart(4, Color4.Blue, Color4.Violet),
|
||||||
foregroundContainer = new BufferedContainer
|
foregroundContainer = new BufferedContainer
|
||||||
{
|
{
|
||||||
Name = "Foreground",
|
Name = "Foreground",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0.8f,
|
Alpha = 0.8f,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Circle
|
new Circle
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.45f),
|
Size = new Vector2(0.45f),
|
||||||
Y = -0.15f,
|
Y = -0.15f,
|
||||||
Colour = Color4.Cyan
|
Colour = Color4.Cyan
|
||||||
},
|
},
|
||||||
new Circle
|
new Circle
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.45f),
|
Size = new Vector2(0.45f),
|
||||||
X = -0.15f,
|
X = -0.15f,
|
||||||
Colour = Color4.Magenta
|
Colour = Color4.Magenta
|
||||||
},
|
},
|
||||||
new Circle
|
new Circle
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.45f),
|
Size = new Vector2(0.45f),
|
||||||
X = 0.15f,
|
X = 0.15f,
|
||||||
Colour = Color4.Yellow
|
Colour = Color4.Yellow
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
colourModeDropdown.Items = Enum.GetNames(typeof(BlendingMode)).Select(n => new KeyValuePair<string, BlendingMode>(n, (BlendingMode)Enum.Parse(typeof(BlendingMode), n)));
|
colourModeDropdown.Items = Enum.GetNames(typeof(BlendingMode)).Select(n => new KeyValuePair<string, BlendingMode>(n, (BlendingMode)Enum.Parse(typeof(BlendingMode), n)));
|
||||||
colourEquation.Items = Enum.GetNames(typeof(BlendingEquation)).Select(n => new KeyValuePair<string, BlendingEquation>(n, (BlendingEquation)Enum.Parse(typeof(BlendingEquation), n)));
|
colourEquation.Items = Enum.GetNames(typeof(BlendingEquation)).Select(n => new KeyValuePair<string, BlendingEquation>(n, (BlendingEquation)Enum.Parse(typeof(BlendingEquation), n)));
|
||||||
alphaEquation.Items = Enum.GetNames(typeof(BlendingEquation)).Select(n => new KeyValuePair<string, BlendingEquation>(n, (BlendingEquation)Enum.Parse(typeof(BlendingEquation), n)));
|
alphaEquation.Items = Enum.GetNames(typeof(BlendingEquation)).Select(n => new KeyValuePair<string, BlendingEquation>(n, (BlendingEquation)Enum.Parse(typeof(BlendingEquation), n)));
|
||||||
|
|
||||||
colourModeDropdown.Current.Value = foregroundContainer.Blending.Mode;
|
colourModeDropdown.Current.Value = foregroundContainer.Blending.Mode;
|
||||||
colourEquation.Current.Value = foregroundContainer.Blending.RGBEquation;
|
colourEquation.Current.Value = foregroundContainer.Blending.RGBEquation;
|
||||||
alphaEquation.Current.Value = foregroundContainer.Blending.AlphaEquation;
|
alphaEquation.Current.Value = foregroundContainer.Blending.AlphaEquation;
|
||||||
|
|
||||||
colourModeDropdown.Current.ValueChanged += v => updateBlending();
|
colourModeDropdown.Current.ValueChanged += v => updateBlending();
|
||||||
colourEquation.Current.ValueChanged += v => updateBlending();
|
colourEquation.Current.ValueChanged += v => updateBlending();
|
||||||
alphaEquation.Current.ValueChanged += v => updateBlending();
|
alphaEquation.Current.ValueChanged += v => updateBlending();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateBlending()
|
private void updateBlending()
|
||||||
{
|
{
|
||||||
foregroundContainer.Blending = new BlendingParameters
|
foregroundContainer.Blending = new BlendingParameters
|
||||||
{
|
{
|
||||||
Mode = colourModeDropdown.Current,
|
Mode = colourModeDropdown.Current,
|
||||||
RGBEquation = colourEquation.Current,
|
RGBEquation = colourEquation.Current,
|
||||||
AlphaEquation = alphaEquation.Current
|
AlphaEquation = alphaEquation.Current
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GradientPart : Box
|
private class GradientPart : Box
|
||||||
{
|
{
|
||||||
public GradientPart(int index, Color4 start, Color4 end)
|
public GradientPart(int index, Color4 start, Color4 end)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
RelativePositionAxes = Axes.Both;
|
RelativePositionAxes = Axes.Both;
|
||||||
Width = 1 / 5f; // Assume 5 gradients
|
Width = 1 / 5f; // Assume 5 gradients
|
||||||
X = 1 / 5f * index;
|
X = 1 / 5f * index;
|
||||||
|
|
||||||
Colour = ColourInfo.GradientHorizontal(start, end);
|
Colour = ColourInfo.GradientHorizontal(start, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,32 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseBufferedContainer : TestCaseMasking
|
public class TestCaseBufferedContainer : TestCaseMasking
|
||||||
{
|
{
|
||||||
private readonly BufferedContainer buffer;
|
private readonly BufferedContainer buffer;
|
||||||
|
|
||||||
public TestCaseBufferedContainer()
|
public TestCaseBufferedContainer()
|
||||||
{
|
{
|
||||||
Remove(TestContainer);
|
Remove(TestContainer);
|
||||||
|
|
||||||
Add(buffer = new BufferedContainer
|
Add(buffer = new BufferedContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[] { TestContainer }
|
Children = new[] { TestContainer }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
buffer.BlurTo(new Vector2(20), 1000).Then().BlurTo(Vector2.Zero, 1000).Loop();
|
buffer.BlurTo(new Vector2(20), 1000).Then().BlurTo(Vector2.Zero, 1000).Loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +1,168 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseCachedBufferedContainer : GridTestCase
|
public class TestCaseCachedBufferedContainer : GridTestCase
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
typeof(BufferedContainer),
|
typeof(BufferedContainer),
|
||||||
typeof(BufferedContainerDrawNode),
|
typeof(BufferedContainerDrawNode),
|
||||||
};
|
};
|
||||||
|
|
||||||
public TestCaseCachedBufferedContainer()
|
public TestCaseCachedBufferedContainer()
|
||||||
: base(5, 2)
|
: base(5, 2)
|
||||||
{
|
{
|
||||||
string[] labels =
|
string[] labels =
|
||||||
{
|
{
|
||||||
"uncached",
|
"uncached",
|
||||||
"cached",
|
"cached",
|
||||||
"uncached with rotation",
|
"uncached with rotation",
|
||||||
"cached with rotation",
|
"cached with rotation",
|
||||||
"uncached with movement",
|
"uncached with movement",
|
||||||
"cached with movement",
|
"cached with movement",
|
||||||
"uncached with parent scale",
|
"uncached with parent scale",
|
||||||
"cached with parent scale",
|
"cached with parent scale",
|
||||||
"uncached with parent scale&fade",
|
"uncached with parent scale&fade",
|
||||||
"cached with parent scale&fade",
|
"cached with parent scale&fade",
|
||||||
};
|
};
|
||||||
|
|
||||||
var boxes = new List<ContainingBox>();
|
var boxes = new List<ContainingBox>();
|
||||||
|
|
||||||
for (int i = 0; i < Rows * Cols; ++i)
|
for (int i = 0; i < Rows * Cols; ++i)
|
||||||
{
|
{
|
||||||
ContainingBox box;
|
ContainingBox box;
|
||||||
|
|
||||||
Cell(i).AddRange(new Drawable[]
|
Cell(i).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = labels[i],
|
Text = labels[i],
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
},
|
},
|
||||||
box = new ContainingBox(i >= 6, i >= 8)
|
box = new ContainingBox(i >= 6, i >= 8)
|
||||||
{
|
{
|
||||||
Child = new CountingBox(i == 2 || i == 3, i == 4 || i == 5)
|
Child = new CountingBox(i == 2 || i == 3, i == 4 || i == 5)
|
||||||
{
|
{
|
||||||
CacheDrawnFrameBuffer = i % 2 == 1,
|
CacheDrawnFrameBuffer = i % 2 == 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
boxes.Add(box);
|
boxes.Add(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddWaitStep(5);
|
AddWaitStep(5);
|
||||||
|
|
||||||
// ensure uncached is always updating children.
|
// ensure uncached is always updating children.
|
||||||
AddAssert("box 0 count > 0", () => boxes[0].Count > 0);
|
AddAssert("box 0 count > 0", () => boxes[0].Count > 0);
|
||||||
AddAssert("even box counts equal", () =>
|
AddAssert("even box counts equal", () =>
|
||||||
boxes[0].Count == boxes[2].Count &&
|
boxes[0].Count == boxes[2].Count &&
|
||||||
boxes[2].Count == boxes[4].Count &&
|
boxes[2].Count == boxes[4].Count &&
|
||||||
boxes[4].Count == boxes[6].Count);
|
boxes[4].Count == boxes[6].Count);
|
||||||
|
|
||||||
// ensure cached is never updating children.
|
// ensure cached is never updating children.
|
||||||
AddAssert("box 1 count is 1", () => boxes[1].Count == 1);
|
AddAssert("box 1 count is 1", () => boxes[1].Count == 1);
|
||||||
|
|
||||||
// ensure rotation changes are invalidating cache (for now).
|
// ensure rotation changes are invalidating cache (for now).
|
||||||
AddAssert("box 2 count > 0", () => boxes[2].Count > 0);
|
AddAssert("box 2 count > 0", () => boxes[2].Count > 0);
|
||||||
AddAssert("box 2 count equals box 3 count", () => boxes[2].Count == boxes[3].Count);
|
AddAssert("box 2 count equals box 3 count", () => boxes[2].Count == boxes[3].Count);
|
||||||
|
|
||||||
// ensure cached with only translation is never updating children.
|
// ensure cached with only translation is never updating children.
|
||||||
AddAssert("box 5 count is 1", () => boxes[1].Count == 1);
|
AddAssert("box 5 count is 1", () => boxes[1].Count == 1);
|
||||||
|
|
||||||
// ensure a parent scaling is invalidating cache.
|
// ensure a parent scaling is invalidating cache.
|
||||||
AddAssert("box 5 count equals box 6 count", () => boxes[5].Count == boxes[6].Count);
|
AddAssert("box 5 count equals box 6 count", () => boxes[5].Count == boxes[6].Count);
|
||||||
|
|
||||||
// ensure we don't break on colour invalidations (due to blanket invalidation logic in Drawable.Invalidate).
|
// ensure we don't break on colour invalidations (due to blanket invalidation logic in Drawable.Invalidate).
|
||||||
AddAssert("box 7 count equals box 8 count", () => boxes[7].Count == boxes[8].Count);
|
AddAssert("box 7 count equals box 8 count", () => boxes[7].Count == boxes[8].Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ContainingBox : Container
|
private class ContainingBox : Container
|
||||||
{
|
{
|
||||||
private readonly bool scaling;
|
private readonly bool scaling;
|
||||||
private readonly bool fading;
|
private readonly bool fading;
|
||||||
|
|
||||||
public ContainingBox(bool scaling, bool fading)
|
public ContainingBox(bool scaling, bool fading)
|
||||||
{
|
{
|
||||||
this.scaling = scaling;
|
this.scaling = scaling;
|
||||||
this.fading = fading;
|
this.fading = fading;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
if (scaling) this.ScaleTo(1.2f, 1000).Then().ScaleTo(1, 1000).Loop();
|
if (scaling) this.ScaleTo(1.2f, 1000).Then().ScaleTo(1, 1000).Loop();
|
||||||
if (fading) this.FadeTo(0.5f, 1000).Then().FadeTo(1, 1000).Loop();
|
if (fading) this.FadeTo(0.5f, 1000).Then().FadeTo(1, 1000).Loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CountingBox : BufferedContainer
|
private class CountingBox : BufferedContainer
|
||||||
{
|
{
|
||||||
private readonly bool rotating;
|
private readonly bool rotating;
|
||||||
private readonly bool moving;
|
private readonly bool moving;
|
||||||
private readonly SpriteText count;
|
private readonly SpriteText count;
|
||||||
public new int Count;
|
public new int Count;
|
||||||
|
|
||||||
public CountingBox(bool rotating = false, bool moving = false)
|
public CountingBox(bool rotating = false, bool moving = false)
|
||||||
{
|
{
|
||||||
this.rotating = rotating;
|
this.rotating = rotating;
|
||||||
this.moving = moving;
|
this.moving = moving;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
|
|
||||||
Scale = new Vector2(0.5f);
|
Scale = new Vector2(0.5f);
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.NavajoWhite,
|
Colour = Color4.NavajoWhite,
|
||||||
},
|
},
|
||||||
count = new SpriteText
|
count = new SpriteText
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
TextSize = 80
|
TextSize = 80
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (RequiresChildrenUpdate)
|
if (RequiresChildrenUpdate)
|
||||||
{
|
{
|
||||||
Count++;
|
Count++;
|
||||||
count.Text = Count.ToString();
|
count.Text = Count.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
if (rotating) this.RotateTo(360, 1000).Loop();
|
if (rotating) this.RotateTo(360, 1000).Loop();
|
||||||
if (moving) this.MoveTo(new Vector2(100, 0), 2000, Easing.InOutSine).Then().MoveTo(new Vector2(0, 0), 2000, Easing.InOutSine).Loop();
|
if (moving) this.MoveTo(new Vector2(100, 0), 2000, Easing.InOutSine).Then().MoveTo(new Vector2(0, 0), 2000, Easing.InOutSine).Loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseCheckboxes : TestCase
|
public class TestCaseCheckboxes : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseCheckboxes()
|
public TestCaseCheckboxes()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 10),
|
Spacing = new Vector2(0, 10),
|
||||||
Padding = new MarginPadding(10),
|
Padding = new MarginPadding(10),
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new BasicCheckbox
|
new BasicCheckbox
|
||||||
{
|
{
|
||||||
LabelText = @"Basic Test"
|
LabelText = @"Basic Test"
|
||||||
},
|
},
|
||||||
new BasicCheckbox
|
new BasicCheckbox
|
||||||
{
|
{
|
||||||
LabelText = @"FadeDuration Test",
|
LabelText = @"FadeDuration Test",
|
||||||
FadeDuration = 300
|
FadeDuration = 300
|
||||||
},
|
},
|
||||||
new ActionsTestCheckbox
|
new ActionsTestCheckbox
|
||||||
{
|
{
|
||||||
LabelText = @"Enabled/Disabled Actions Test",
|
LabelText = @"Enabled/Disabled Actions Test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ActionsTestCheckbox : BasicCheckbox
|
public class ActionsTestCheckbox : BasicCheckbox
|
||||||
{
|
{
|
||||||
public ActionsTestCheckbox()
|
public ActionsTestCheckbox()
|
||||||
{
|
{
|
||||||
Current.ValueChanged += v => this.RotateTo(v ? 45 : 0, 100);
|
Current.ValueChanged += v => this.RotateTo(v ? 45 : 0, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,53 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description(@"Checking for bugged corner radius")]
|
[System.ComponentModel.Description(@"Checking for bugged corner radius")]
|
||||||
public class TestCaseCircularContainer : TestCase
|
public class TestCaseCircularContainer : TestCase
|
||||||
{
|
{
|
||||||
private SingleUpdateCircularContainer container;
|
private SingleUpdateCircularContainer container;
|
||||||
|
|
||||||
public TestCaseCircularContainer()
|
public TestCaseCircularContainer()
|
||||||
{
|
{
|
||||||
AddStep("128x128 box", () => addContainer(new Vector2(128)));
|
AddStep("128x128 box", () => addContainer(new Vector2(128)));
|
||||||
AddAssert("Expect CornerRadius = 64", () => Precision.AlmostEquals(container.CornerRadius, 64));
|
AddAssert("Expect CornerRadius = 64", () => Precision.AlmostEquals(container.CornerRadius, 64));
|
||||||
AddStep("128x64 box", () => addContainer(new Vector2(128, 64)));
|
AddStep("128x64 box", () => addContainer(new Vector2(128, 64)));
|
||||||
AddAssert("Expect CornerRadius = 32", () => Precision.AlmostEquals(container.CornerRadius, 32));
|
AddAssert("Expect CornerRadius = 32", () => Precision.AlmostEquals(container.CornerRadius, 32));
|
||||||
AddStep("64x128 box", () => addContainer(new Vector2(64, 128)));
|
AddStep("64x128 box", () => addContainer(new Vector2(64, 128)));
|
||||||
AddAssert("Expect CornerRadius = 32", () => Precision.AlmostEquals(container.CornerRadius, 32));
|
AddAssert("Expect CornerRadius = 32", () => Precision.AlmostEquals(container.CornerRadius, 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContainer(Vector2 size)
|
private void addContainer(Vector2 size)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
Add(container = new SingleUpdateCircularContainer
|
Add(container = new SingleUpdateCircularContainer
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new Box { Size = size }
|
Child = new Box { Size = size }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SingleUpdateCircularContainer : CircularContainer
|
private class SingleUpdateCircularContainer : CircularContainer
|
||||||
{
|
{
|
||||||
private bool firstUpdate = true;
|
private bool firstUpdate = true;
|
||||||
|
|
||||||
public override bool UpdateSubTree()
|
public override bool UpdateSubTree()
|
||||||
{
|
{
|
||||||
if (!firstUpdate)
|
if (!firstUpdate)
|
||||||
return true;
|
return true;
|
||||||
firstUpdate = false;
|
firstUpdate = false;
|
||||||
|
|
||||||
return base.UpdateSubTree();
|
return base.UpdateSubTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,191 +1,191 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseCircularProgress : TestCase
|
public class TestCaseCircularProgress : TestCase
|
||||||
{
|
{
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(CircularProgress), typeof(CircularProgressDrawNode), typeof(CircularProgressDrawNodeSharedData) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(CircularProgress), typeof(CircularProgressDrawNode), typeof(CircularProgressDrawNodeSharedData) };
|
||||||
|
|
||||||
private readonly CircularProgress clock;
|
private readonly CircularProgress clock;
|
||||||
|
|
||||||
private int rotateMode;
|
private int rotateMode;
|
||||||
private const double period = 4000;
|
private const double period = 4000;
|
||||||
private const double transition_period = 2000;
|
private const double transition_period = 2000;
|
||||||
|
|
||||||
private readonly Texture gradientTextureHorizontal;
|
private readonly Texture gradientTextureHorizontal;
|
||||||
private readonly Texture gradientTextureVertical;
|
private readonly Texture gradientTextureVertical;
|
||||||
private readonly Texture gradientTextureBoth;
|
private readonly Texture gradientTextureBoth;
|
||||||
|
|
||||||
public TestCaseCircularProgress()
|
public TestCaseCircularProgress()
|
||||||
{
|
{
|
||||||
const int width = 128;
|
const int width = 128;
|
||||||
byte[] data = new byte[width * 4];
|
byte[] data = new byte[width * 4];
|
||||||
|
|
||||||
gradientTextureHorizontal = new Texture(width, 1, true);
|
gradientTextureHorizontal = new Texture(width, 1, true);
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < width; ++i)
|
||||||
{
|
{
|
||||||
float brightness = (float)i / (width - 1);
|
float brightness = (float)i / (width - 1);
|
||||||
int index = i * 4;
|
int index = i * 4;
|
||||||
data[index + 0] = (byte)(128 + (1 - brightness) * 127);
|
data[index + 0] = (byte)(128 + (1 - brightness) * 127);
|
||||||
data[index + 1] = (byte)(128 + brightness * 127);
|
data[index + 1] = (byte)(128 + brightness * 127);
|
||||||
data[index + 2] = 128;
|
data[index + 2] = 128;
|
||||||
data[index + 3] = 255;
|
data[index + 3] = 255;
|
||||||
}
|
}
|
||||||
gradientTextureHorizontal.SetData(new TextureUpload(data));
|
gradientTextureHorizontal.SetData(new TextureUpload(data));
|
||||||
|
|
||||||
gradientTextureVertical = new Texture(1, width, true);
|
gradientTextureVertical = new Texture(1, width, true);
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < width; ++i)
|
||||||
{
|
{
|
||||||
float brightness = (float)i / (width - 1);
|
float brightness = (float)i / (width - 1);
|
||||||
int index = i * 4;
|
int index = i * 4;
|
||||||
data[index + 0] = (byte)(128 + (1 - brightness) * 127);
|
data[index + 0] = (byte)(128 + (1 - brightness) * 127);
|
||||||
data[index + 1] = (byte)(128 + brightness * 127);
|
data[index + 1] = (byte)(128 + brightness * 127);
|
||||||
data[index + 2] = 128;
|
data[index + 2] = 128;
|
||||||
data[index + 3] = 255;
|
data[index + 3] = 255;
|
||||||
}
|
}
|
||||||
gradientTextureVertical.SetData(new TextureUpload(data));
|
gradientTextureVertical.SetData(new TextureUpload(data));
|
||||||
|
|
||||||
byte[] data2 = new byte[width * width * 4];
|
byte[] data2 = new byte[width * width * 4];
|
||||||
gradientTextureBoth = new Texture(width, width, true);
|
gradientTextureBoth = new Texture(width, width, true);
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < width; ++i)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < width; ++j)
|
for (int j = 0; j < width; ++j)
|
||||||
{
|
{
|
||||||
float brightness = (float)i / (width - 1);
|
float brightness = (float)i / (width - 1);
|
||||||
float brightness2 = (float)j / (width - 1);
|
float brightness2 = (float)j / (width - 1);
|
||||||
int index = i * 4 * width + j * 4;
|
int index = i * 4 * width + j * 4;
|
||||||
data2[index + 0] = (byte)(128 + (1 + brightness - brightness2) / 2 * 127);
|
data2[index + 0] = (byte)(128 + (1 + brightness - brightness2) / 2 * 127);
|
||||||
data2[index + 1] = (byte)(128 + (1 + brightness2 - brightness) / 2 * 127);
|
data2[index + 1] = (byte)(128 + (1 + brightness2 - brightness) / 2 * 127);
|
||||||
data2[index + 2] = (byte)(128 + (brightness + brightness2) / 2 * 127);
|
data2[index + 2] = (byte)(128 + (brightness + brightness2) / 2 * 127);
|
||||||
data2[index + 3] = 255;
|
data2[index + 3] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gradientTextureBoth.SetData(new TextureUpload(data2));
|
gradientTextureBoth.SetData(new TextureUpload(data2));
|
||||||
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
clock = new CircularProgress
|
clock = new CircularProgress
|
||||||
{
|
{
|
||||||
Width = 0.8f,
|
Width = 0.8f,
|
||||||
Height = 0.8f,
|
Height = 0.8f,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AddStep("Forward", delegate { rotateMode = 1; });
|
AddStep("Forward", delegate { rotateMode = 1; });
|
||||||
AddStep("Backward", delegate { rotateMode = 2; });
|
AddStep("Backward", delegate { rotateMode = 2; });
|
||||||
AddStep("Transition Focus", delegate { rotateMode = 3; });
|
AddStep("Transition Focus", delegate { rotateMode = 3; });
|
||||||
AddStep("Transition Focus 2", delegate { rotateMode = 4; });
|
AddStep("Transition Focus 2", delegate { rotateMode = 4; });
|
||||||
AddStep("Forward/Backward", delegate { rotateMode = 0; });
|
AddStep("Forward/Backward", delegate { rotateMode = 0; });
|
||||||
|
|
||||||
AddStep("Horizontal Gradient Texture", delegate { setTexture(1); });
|
AddStep("Horizontal Gradient Texture", delegate { setTexture(1); });
|
||||||
AddStep("Vertical Gradient Texture", delegate { setTexture(2); });
|
AddStep("Vertical Gradient Texture", delegate { setTexture(2); });
|
||||||
AddStep("2D Graident Texture", delegate { setTexture(3); });
|
AddStep("2D Graident Texture", delegate { setTexture(3); });
|
||||||
AddStep("White Texture", delegate { setTexture(0); });
|
AddStep("White Texture", delegate { setTexture(0); });
|
||||||
|
|
||||||
AddStep("Red Colour", delegate { setColour(1); });
|
AddStep("Red Colour", delegate { setColour(1); });
|
||||||
AddStep("Horzontal Gradient Colour", delegate { setColour(2); });
|
AddStep("Horzontal Gradient Colour", delegate { setColour(2); });
|
||||||
AddStep("Vertical Gradient Colour", delegate { setColour(3); });
|
AddStep("Vertical Gradient Colour", delegate { setColour(3); });
|
||||||
AddStep("2D Gradient Colour", delegate { setColour(4); });
|
AddStep("2D Gradient Colour", delegate { setColour(4); });
|
||||||
AddStep("White Colour", delegate { setColour(0); });
|
AddStep("White Colour", delegate { setColour(0); });
|
||||||
|
|
||||||
AddSliderStep("Fill", 0, 10, 10, fill => clock.InnerRadius = fill / 10f);
|
AddSliderStep("Fill", 0, 10, 10, fill => clock.InnerRadius = fill / 10f);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
switch (rotateMode)
|
switch (rotateMode)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
clock.Current.Value = Time.Current % (period * 2) / period - 1;
|
clock.Current.Value = Time.Current % (period * 2) / period - 1;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
clock.Current.Value = Time.Current % period / period;
|
clock.Current.Value = Time.Current % period / period;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
clock.Current.Value = Time.Current % period / period - 1;
|
clock.Current.Value = Time.Current % period / period - 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
clock.Current.Value = Time.Current % transition_period / transition_period / 5 - 0.1f;
|
clock.Current.Value = Time.Current % transition_period / transition_period / 5 - 0.1f;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
clock.Current.Value = (Time.Current % transition_period / transition_period / 5 - 0.1f + 2) % 2 - 1;
|
clock.Current.Value = (Time.Current % transition_period / transition_period / 5 - 0.1f + 2) % 2 - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTexture(int textureMode)
|
private void setTexture(int textureMode)
|
||||||
{
|
{
|
||||||
switch (textureMode)
|
switch (textureMode)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
clock.Texture = Texture.WhitePixel;
|
clock.Texture = Texture.WhitePixel;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
clock.Texture = gradientTextureHorizontal;
|
clock.Texture = gradientTextureHorizontal;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
clock.Texture = gradientTextureVertical;
|
clock.Texture = gradientTextureVertical;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
clock.Texture = gradientTextureBoth;
|
clock.Texture = gradientTextureBoth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setColour(int colourMode)
|
private void setColour(int colourMode)
|
||||||
{
|
{
|
||||||
switch (colourMode)
|
switch (colourMode)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
clock.Colour = new Color4(255, 255, 255, 255);
|
clock.Colour = new Color4(255, 255, 255, 255);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
clock.Colour = new Color4(255, 128, 128, 255);
|
clock.Colour = new Color4(255, 128, 128, 255);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
clock.Colour = new ColourInfo
|
clock.Colour = new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = new Color4(255, 128, 128, 255),
|
TopLeft = new Color4(255, 128, 128, 255),
|
||||||
TopRight = new Color4(128, 255, 128, 255),
|
TopRight = new Color4(128, 255, 128, 255),
|
||||||
BottomLeft = new Color4(255, 128, 128, 255),
|
BottomLeft = new Color4(255, 128, 128, 255),
|
||||||
BottomRight = new Color4(128, 255, 128, 255),
|
BottomRight = new Color4(128, 255, 128, 255),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
clock.Colour = new ColourInfo
|
clock.Colour = new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = new Color4(255, 128, 128, 255),
|
TopLeft = new Color4(255, 128, 128, 255),
|
||||||
TopRight = new Color4(255, 128, 128, 255),
|
TopRight = new Color4(255, 128, 128, 255),
|
||||||
BottomLeft = new Color4(128, 255, 128, 255),
|
BottomLeft = new Color4(128, 255, 128, 255),
|
||||||
BottomRight = new Color4(128, 255, 128, 255),
|
BottomRight = new Color4(128, 255, 128, 255),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
clock.Colour = new ColourInfo
|
clock.Colour = new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = new Color4(255, 128, 128, 255),
|
TopLeft = new Color4(255, 128, 128, 255),
|
||||||
TopRight = new Color4(128, 255, 128, 255),
|
TopRight = new Color4(128, 255, 128, 255),
|
||||||
BottomLeft = new Color4(128, 128, 255, 255),
|
BottomLeft = new Color4(128, 128, 255, 255),
|
||||||
BottomRight = new Color4(255, 255, 255, 255),
|
BottomRight = new Color4(255, 255, 255, 255),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseColourGradient : GridTestCase
|
public class TestCaseColourGradient : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseColourGradient() : base(2, 2)
|
public TestCaseColourGradient() : base(2, 2)
|
||||||
{
|
{
|
||||||
Color4 transparentBlack = new Color4(0, 0, 0, 0);
|
Color4 transparentBlack = new Color4(0, 0, 0, 0);
|
||||||
|
|
||||||
ColourInfo[] colours =
|
ColourInfo[] colours =
|
||||||
{
|
{
|
||||||
new ColourInfo
|
new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = Color4.White,
|
TopLeft = Color4.White,
|
||||||
BottomLeft = Color4.Blue,
|
BottomLeft = Color4.Blue,
|
||||||
TopRight = Color4.Red,
|
TopRight = Color4.Red,
|
||||||
BottomRight = Color4.Green,
|
BottomRight = Color4.Green,
|
||||||
},
|
},
|
||||||
new ColourInfo
|
new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = Color4.White,
|
TopLeft = Color4.White,
|
||||||
BottomLeft = Color4.White,
|
BottomLeft = Color4.White,
|
||||||
TopRight = Color4.Black,
|
TopRight = Color4.Black,
|
||||||
BottomRight = Color4.Black,
|
BottomRight = Color4.Black,
|
||||||
},
|
},
|
||||||
new ColourInfo
|
new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = Color4.White,
|
TopLeft = Color4.White,
|
||||||
BottomLeft = Color4.White,
|
BottomLeft = Color4.White,
|
||||||
TopRight = Color4.Transparent,
|
TopRight = Color4.Transparent,
|
||||||
BottomRight = Color4.Transparent,
|
BottomRight = Color4.Transparent,
|
||||||
},
|
},
|
||||||
new ColourInfo
|
new ColourInfo
|
||||||
{
|
{
|
||||||
TopLeft = Color4.White,
|
TopLeft = Color4.White,
|
||||||
BottomLeft = Color4.White,
|
BottomLeft = Color4.White,
|
||||||
TopRight = transparentBlack,
|
TopRight = transparentBlack,
|
||||||
BottomRight = transparentBlack,
|
BottomRight = transparentBlack,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
string[] labels =
|
string[] labels =
|
||||||
{
|
{
|
||||||
"Colours",
|
"Colours",
|
||||||
"White to black (linear brightness gradient)",
|
"White to black (linear brightness gradient)",
|
||||||
"White to transparent white (sRGB brightness gradient)",
|
"White to transparent white (sRGB brightness gradient)",
|
||||||
"White to transparent black (mixed brightness gradient)",
|
"White to transparent black (mixed brightness gradient)",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < Rows * Cols; ++i)
|
for (int i = 0; i < Rows * Cols; ++i)
|
||||||
{
|
{
|
||||||
Cell(i).AddRange(new Drawable[]
|
Cell(i).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = labels[i],
|
Text = labels[i],
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
Colour = colours[0],
|
Colour = colours[0],
|
||||||
},
|
},
|
||||||
boxes[i] = new Box
|
boxes[i] = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Colour = colours[i],
|
Colour = colours[i],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Box[] boxes = new Box[4];
|
private readonly Box[] boxes = new Box[4];
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
foreach (Box box in boxes)
|
foreach (Box box in boxes)
|
||||||
box.Rotation += 0.01f;
|
box.Rotation += 0.01f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,123 +1,123 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("ensure valid container state in various scenarios")]
|
[System.ComponentModel.Description("ensure valid container state in various scenarios")]
|
||||||
public class TestCaseContainerState : TestCase
|
public class TestCaseContainerState : TestCase
|
||||||
{
|
{
|
||||||
private readonly Container container;
|
private readonly Container container;
|
||||||
|
|
||||||
public TestCaseContainerState()
|
public TestCaseContainerState()
|
||||||
{
|
{
|
||||||
Add(container = new Container());
|
Add(container = new Container());
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
testLoadedMultipleAdds();
|
testLoadedMultipleAdds();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if a drawable can be added to a container, removed, and then re-added to the same container.
|
/// Tests if a drawable can be added to a container, removed, and then re-added to the same container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestPreLoadReAdding()
|
public void TestPreLoadReAdding()
|
||||||
{
|
{
|
||||||
var sprite = new Sprite();
|
var sprite = new Sprite();
|
||||||
|
|
||||||
// Add
|
// Add
|
||||||
Assert.DoesNotThrow(() => container.Add(sprite));
|
Assert.DoesNotThrow(() => container.Add(sprite));
|
||||||
Assert.IsTrue(container.Contains(sprite));
|
Assert.IsTrue(container.Contains(sprite));
|
||||||
|
|
||||||
// Remove
|
// Remove
|
||||||
Assert.DoesNotThrow(() => container.Remove(sprite));
|
Assert.DoesNotThrow(() => container.Remove(sprite));
|
||||||
Assert.IsFalse(container.Contains(sprite));
|
Assert.IsFalse(container.Contains(sprite));
|
||||||
|
|
||||||
// Re-add
|
// Re-add
|
||||||
Assert.DoesNotThrow(() => container.Add(sprite));
|
Assert.DoesNotThrow(() => container.Add(sprite));
|
||||||
Assert.IsTrue(container.Contains(sprite));
|
Assert.IsTrue(container.Contains(sprite));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether adding a child to multiple containers by abusing <see cref="Container{T}.Children"/>
|
/// Tests whether adding a child to multiple containers by abusing <see cref="Container{T}.Children"/>
|
||||||
/// results in a <see cref="InvalidOperationException"/>.
|
/// results in a <see cref="InvalidOperationException"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestPreLoadMultipleAdds()
|
public void TestPreLoadMultipleAdds()
|
||||||
{
|
{
|
||||||
// Non-async
|
// Non-async
|
||||||
Assert.Throws<InvalidOperationException>(() =>
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
{
|
{
|
||||||
container.Add(new Container
|
container.Add(new Container
|
||||||
{
|
{
|
||||||
// Container is an IReadOnlyList<T>, so Children can accept a Container.
|
// Container is an IReadOnlyList<T>, so Children can accept a Container.
|
||||||
// This further means that CompositeDrawable.AddInternal will try to add all of
|
// This further means that CompositeDrawable.AddInternal will try to add all of
|
||||||
// the children of the Container that was set to Children, which should throw an exception
|
// the children of the Container that was set to Children, which should throw an exception
|
||||||
Children = new Container { Child = new Container() }
|
Children = new Container { Child = new Container() }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The same as <see cref="TestPreLoadMultipleAdds"/> however instead runs after the container is loaded.
|
/// The same as <see cref="TestPreLoadMultipleAdds"/> however instead runs after the container is loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void testLoadedMultipleAdds()
|
private void testLoadedMultipleAdds()
|
||||||
{
|
{
|
||||||
AddAssert("Test loaded multiple adds", () =>
|
AddAssert("Test loaded multiple adds", () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
container.Add(new Container
|
container.Add(new Container
|
||||||
{
|
{
|
||||||
// Container is an IReadOnlyList<T>, so Children can accept a Container.
|
// Container is an IReadOnlyList<T>, so Children can accept a Container.
|
||||||
// This further means that CompositeDrawable.AddInternal will try to add all of
|
// This further means that CompositeDrawable.AddInternal will try to add all of
|
||||||
// the children of the Container that was set to Children, which should throw an exception
|
// the children of the Container that was set to Children, which should throw an exception
|
||||||
Children = new Container { Child = new Container() }
|
Children = new Container { Child = new Container() }
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether the result of a <see cref="Container{T}.Contains(T)"/> operation is valid between multiple containers.
|
/// Tests whether the result of a <see cref="Container{T}.Contains(T)"/> operation is valid between multiple containers.
|
||||||
/// This tests whether the comparator + equality operation in <see cref="CompositeDrawable.IndexOfInternal(Graphics.Drawable)"/> is valid.
|
/// This tests whether the comparator + equality operation in <see cref="CompositeDrawable.IndexOfInternal(Graphics.Drawable)"/> is valid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestContainerContains()
|
public void TestContainerContains()
|
||||||
{
|
{
|
||||||
var drawableA = new Sprite();
|
var drawableA = new Sprite();
|
||||||
var drawableB = new Sprite();
|
var drawableB = new Sprite();
|
||||||
var containerA = new Container { Child = drawableA };
|
var containerA = new Container { Child = drawableA };
|
||||||
var containerB = new Container { Child = drawableB };
|
var containerB = new Container { Child = drawableB };
|
||||||
|
|
||||||
var newContainer = new Container<Container> { Children = new[] { containerA, containerB } };
|
var newContainer = new Container<Container> { Children = new[] { containerA, containerB } };
|
||||||
|
|
||||||
// Because drawableA and drawableB have been added to separate containers,
|
// Because drawableA and drawableB have been added to separate containers,
|
||||||
// they will both have Depth = 0 and ChildID = 1, which leads to edge cases if a
|
// they will both have Depth = 0 and ChildID = 1, which leads to edge cases if a
|
||||||
// sorting comparer that doesn't compare references is used for Contains().
|
// sorting comparer that doesn't compare references is used for Contains().
|
||||||
// If this is not handled properly, it may have devastating effects in, e.g. Remove().
|
// If this is not handled properly, it may have devastating effects in, e.g. Remove().
|
||||||
|
|
||||||
Assert.IsTrue(newContainer.First(c => c.Contains(drawableA)) == containerA);
|
Assert.IsTrue(newContainer.First(c => c.Contains(drawableA)) == containerA);
|
||||||
Assert.IsTrue(newContainer.First(c => c.Contains(drawableB)) == containerB);
|
Assert.IsTrue(newContainer.First(c => c.Contains(drawableB)) == containerB);
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => newContainer.First(c => c.Contains(drawableA)).Remove(drawableA));
|
Assert.DoesNotThrow(() => newContainer.First(c => c.Contains(drawableA)).Remove(drawableA));
|
||||||
Assert.DoesNotThrow(() => newContainer.First(c => c.Contains(drawableB)).Remove(drawableB));
|
Assert.DoesNotThrow(() => newContainer.First(c => c.Contains(drawableB)).Remove(drawableB));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +1,79 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseContextMenu : TestCase
|
public class TestCaseContextMenu : TestCase
|
||||||
{
|
{
|
||||||
private const int start_time = 0;
|
private const int start_time = 0;
|
||||||
private const int duration = 1000;
|
private const int duration = 1000;
|
||||||
|
|
||||||
private readonly ContextMenuBox movingBox;
|
private readonly ContextMenuBox movingBox;
|
||||||
|
|
||||||
private ContextMenuBox makeBox(Anchor anchor)
|
private ContextMenuBox makeBox(Anchor anchor)
|
||||||
{
|
{
|
||||||
return new ContextMenuBox
|
return new ContextMenuBox
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Anchor = anchor,
|
Anchor = anchor,
|
||||||
Origin = anchor,
|
Origin = anchor,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseContextMenu()
|
public TestCaseContextMenu()
|
||||||
{
|
{
|
||||||
Add(new ContextMenuContainer
|
Add(new ContextMenuContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
makeBox(Anchor.TopLeft),
|
makeBox(Anchor.TopLeft),
|
||||||
makeBox(Anchor.TopRight),
|
makeBox(Anchor.TopRight),
|
||||||
makeBox(Anchor.BottomLeft),
|
makeBox(Anchor.BottomLeft),
|
||||||
makeBox(Anchor.BottomRight),
|
makeBox(Anchor.BottomRight),
|
||||||
movingBox = makeBox(Anchor.Centre),
|
movingBox = makeBox(Anchor.Centre),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
// Move box along a square trajectory
|
// Move box along a square trajectory
|
||||||
movingBox.MoveTo(new Vector2(0, 100), duration)
|
movingBox.MoveTo(new Vector2(0, 100), duration)
|
||||||
.Then().MoveTo(new Vector2(100, 100), duration)
|
.Then().MoveTo(new Vector2(100, 100), duration)
|
||||||
.Then().MoveTo(new Vector2(100, 0), duration)
|
.Then().MoveTo(new Vector2(100, 0), duration)
|
||||||
.Then().MoveTo(Vector2.Zero, duration)
|
.Then().MoveTo(Vector2.Zero, duration)
|
||||||
.Loop();
|
.Loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ContextMenuBox : Container, IHasContextMenu
|
private class ContextMenuBox : Container, IHasContextMenu
|
||||||
{
|
{
|
||||||
public MenuItem[] ContextMenuItems => new[]
|
public MenuItem[] ContextMenuItems => new[]
|
||||||
{
|
{
|
||||||
new MenuItem(@"Change width", () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
new MenuItem(@"Change width", () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
||||||
new MenuItem(@"Change height", () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
new MenuItem(@"Change height", () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
||||||
new MenuItem(@"Change width back", () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
new MenuItem(@"Change width back", () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
||||||
new MenuItem(@"Change height back", () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
new MenuItem(@"Change height back", () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,219 +1,219 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseCoordinateSpaces : TestCase
|
public class TestCaseCoordinateSpaces : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseCoordinateSpaces()
|
public TestCaseCoordinateSpaces()
|
||||||
{
|
{
|
||||||
AddStep("0-1 space", () => loadCase(0));
|
AddStep("0-1 space", () => loadCase(0));
|
||||||
AddStep("0-150 space", () => loadCase(1));
|
AddStep("0-150 space", () => loadCase(1));
|
||||||
AddStep("50-200 space", () => loadCase(2));
|
AddStep("50-200 space", () => loadCase(2));
|
||||||
AddStep("150-(-50) space", () => loadCase(3));
|
AddStep("150-(-50) space", () => loadCase(3));
|
||||||
AddStep("0-300 space", () => loadCase(4));
|
AddStep("0-300 space", () => loadCase(4));
|
||||||
AddStep("-250-250 space", () => loadCase(5));
|
AddStep("-250-250 space", () => loadCase(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCase(int i)
|
private void loadCase(int i)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
HorizontalVisualiser h;
|
HorizontalVisualiser h;
|
||||||
Add(h = new HorizontalVisualiser
|
Add(h = new HorizontalVisualiser
|
||||||
{
|
{
|
||||||
Size = new Vector2(200, 50),
|
Size = new Vector2(200, 50),
|
||||||
X = 150
|
X = 150
|
||||||
});
|
});
|
||||||
|
|
||||||
switch (i)
|
switch (i)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
h.CreateMarkerAt(-0.1f);
|
h.CreateMarkerAt(-0.1f);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(0.1f);
|
h.CreateMarkerAt(0.1f);
|
||||||
h.CreateMarkerAt(0.3f);
|
h.CreateMarkerAt(0.3f);
|
||||||
h.CreateMarkerAt(0.7f);
|
h.CreateMarkerAt(0.7f);
|
||||||
h.CreateMarkerAt(0.9f);
|
h.CreateMarkerAt(0.9f);
|
||||||
h.CreateMarkerAt(1f);
|
h.CreateMarkerAt(1f);
|
||||||
h.CreateMarkerAt(1.1f);
|
h.CreateMarkerAt(1.1f);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
h.RelativeChildSize = new Vector2(150, 1);
|
h.RelativeChildSize = new Vector2(150, 1);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(50);
|
h.CreateMarkerAt(50);
|
||||||
h.CreateMarkerAt(100);
|
h.CreateMarkerAt(100);
|
||||||
h.CreateMarkerAt(150);
|
h.CreateMarkerAt(150);
|
||||||
h.CreateMarkerAt(200);
|
h.CreateMarkerAt(200);
|
||||||
h.CreateMarkerAt(250);
|
h.CreateMarkerAt(250);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
h.RelativeChildOffset = new Vector2(50, 0);
|
h.RelativeChildOffset = new Vector2(50, 0);
|
||||||
h.RelativeChildSize = new Vector2(150, 1);
|
h.RelativeChildSize = new Vector2(150, 1);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(50);
|
h.CreateMarkerAt(50);
|
||||||
h.CreateMarkerAt(100);
|
h.CreateMarkerAt(100);
|
||||||
h.CreateMarkerAt(150);
|
h.CreateMarkerAt(150);
|
||||||
h.CreateMarkerAt(200);
|
h.CreateMarkerAt(200);
|
||||||
h.CreateMarkerAt(250);
|
h.CreateMarkerAt(250);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
h.RelativeChildOffset = new Vector2(150, 0);
|
h.RelativeChildOffset = new Vector2(150, 0);
|
||||||
h.RelativeChildSize = new Vector2(-200, 1);
|
h.RelativeChildSize = new Vector2(-200, 1);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(50);
|
h.CreateMarkerAt(50);
|
||||||
h.CreateMarkerAt(100);
|
h.CreateMarkerAt(100);
|
||||||
h.CreateMarkerAt(150);
|
h.CreateMarkerAt(150);
|
||||||
h.CreateMarkerAt(200);
|
h.CreateMarkerAt(200);
|
||||||
h.CreateMarkerAt(250);
|
h.CreateMarkerAt(250);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
h.RelativeChildOffset = new Vector2(0, 0);
|
h.RelativeChildOffset = new Vector2(0, 0);
|
||||||
h.RelativeChildSize = new Vector2(300, 1);
|
h.RelativeChildSize = new Vector2(300, 1);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(50);
|
h.CreateMarkerAt(50);
|
||||||
h.CreateMarkerAt(100);
|
h.CreateMarkerAt(100);
|
||||||
h.CreateMarkerAt(150);
|
h.CreateMarkerAt(150);
|
||||||
h.CreateMarkerAt(200);
|
h.CreateMarkerAt(200);
|
||||||
h.CreateMarkerAt(250);
|
h.CreateMarkerAt(250);
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
h.RelativeChildOffset = new Vector2(-250, 0);
|
h.RelativeChildOffset = new Vector2(-250, 0);
|
||||||
h.RelativeChildSize = new Vector2(500, 1);
|
h.RelativeChildSize = new Vector2(500, 1);
|
||||||
h.CreateMarkerAt(-300);
|
h.CreateMarkerAt(-300);
|
||||||
h.CreateMarkerAt(-200);
|
h.CreateMarkerAt(-200);
|
||||||
h.CreateMarkerAt(-100);
|
h.CreateMarkerAt(-100);
|
||||||
h.CreateMarkerAt(0);
|
h.CreateMarkerAt(0);
|
||||||
h.CreateMarkerAt(100);
|
h.CreateMarkerAt(100);
|
||||||
h.CreateMarkerAt(200);
|
h.CreateMarkerAt(200);
|
||||||
h.CreateMarkerAt(300);
|
h.CreateMarkerAt(300);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HorizontalVisualiser : Visualiser
|
private class HorizontalVisualiser : Visualiser
|
||||||
{
|
{
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
Left.Text = $"X = {RelativeChildOffset.X.ToString(CultureInfo.InvariantCulture)}";
|
Left.Text = $"X = {RelativeChildOffset.X.ToString(CultureInfo.InvariantCulture)}";
|
||||||
Right.Text = $"X = {(RelativeChildOffset.X + RelativeChildSize.X).ToString(CultureInfo.InvariantCulture)}";
|
Right.Text = $"X = {(RelativeChildOffset.X + RelativeChildSize.X).ToString(CultureInfo.InvariantCulture)}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private abstract class Visualiser : Container
|
private abstract class Visualiser : Container
|
||||||
{
|
{
|
||||||
public new Vector2 RelativeChildSize
|
public new Vector2 RelativeChildSize
|
||||||
{
|
{
|
||||||
protected get { return innerContainer.RelativeChildSize; }
|
protected get { return innerContainer.RelativeChildSize; }
|
||||||
set { innerContainer.RelativeChildSize = value; }
|
set { innerContainer.RelativeChildSize = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public new Vector2 RelativeChildOffset
|
public new Vector2 RelativeChildOffset
|
||||||
{
|
{
|
||||||
protected get { return innerContainer.RelativeChildOffset; }
|
protected get { return innerContainer.RelativeChildOffset; }
|
||||||
set { innerContainer.RelativeChildOffset = value; }
|
set { innerContainer.RelativeChildOffset = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Container innerContainer;
|
private readonly Container innerContainer;
|
||||||
|
|
||||||
protected readonly SpriteText Left;
|
protected readonly SpriteText Left;
|
||||||
protected readonly SpriteText Right;
|
protected readonly SpriteText Right;
|
||||||
|
|
||||||
protected Visualiser()
|
protected Visualiser()
|
||||||
{
|
{
|
||||||
Height = 50;
|
Height = 50;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Left marker",
|
Name = "Left marker",
|
||||||
Colour = Color4.Gray,
|
Colour = Color4.Gray,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
},
|
},
|
||||||
Left = new SpriteText
|
Left = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Y = 6
|
Y = 6
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Centre line",
|
Name = "Centre line",
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Colour = Color4.Gray,
|
Colour = Color4.Gray,
|
||||||
RelativeSizeAxes = Axes.X
|
RelativeSizeAxes = Axes.X
|
||||||
},
|
},
|
||||||
innerContainer = new Container
|
innerContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Right marker",
|
Name = "Right marker",
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Colour = Color4.Gray,
|
Colour = Color4.Gray,
|
||||||
RelativeSizeAxes = Axes.Y
|
RelativeSizeAxes = Axes.Y
|
||||||
},
|
},
|
||||||
Right = new SpriteText
|
Right = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Y = 6
|
Y = 6
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateMarkerAt(float x)
|
public void CreateMarkerAt(float x)
|
||||||
{
|
{
|
||||||
innerContainer.Add(new Container
|
innerContainer.Add(new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
X = x,
|
X = x,
|
||||||
Colour = Color4.Yellow,
|
Colour = Color4.Yellow,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Centre marker horizontal",
|
Name = "Centre marker horizontal",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(8, 1)
|
Size = new Vector2(8, 1)
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Centre marker vertical",
|
Name = "Centre marker vertical",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(1, 8)
|
Size = new Vector2(1, 8)
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Y = 6,
|
Y = 6,
|
||||||
BypassAutoSizeAxes = Axes.Both,
|
BypassAutoSizeAxes = Axes.Both,
|
||||||
Text = x.ToString(CultureInfo.InvariantCulture)
|
Text = x.ToString(CultureInfo.InvariantCulture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,100 +1,100 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseCountingText : TestCase
|
public class TestCaseCountingText : TestCase
|
||||||
{
|
{
|
||||||
private readonly Bindable<CountType> countType = new Bindable<CountType>();
|
private readonly Bindable<CountType> countType = new Bindable<CountType>();
|
||||||
|
|
||||||
public TestCaseCountingText()
|
public TestCaseCountingText()
|
||||||
{
|
{
|
||||||
Counter counter;
|
Counter counter;
|
||||||
|
|
||||||
BasicDropdown<CountType> typeDropdown;
|
BasicDropdown<CountType> typeDropdown;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
typeDropdown = new BasicDropdown<CountType>
|
typeDropdown = new BasicDropdown<CountType>
|
||||||
{
|
{
|
||||||
Position = new Vector2(10),
|
Position = new Vector2(10),
|
||||||
Width = 150,
|
Width = 150,
|
||||||
},
|
},
|
||||||
counter = new TestTextCounter(createResult)
|
counter = new TestTextCounter(createResult)
|
||||||
{
|
{
|
||||||
Position = new Vector2(180)
|
Position = new Vector2(180)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typeDropdown.Items = Enum.GetNames(typeof(CountType)).Select(n => new KeyValuePair<string, CountType>(n, (CountType)Enum.Parse(typeof(CountType), n)));
|
typeDropdown.Items = Enum.GetNames(typeof(CountType)).Select(n => new KeyValuePair<string, CountType>(n, (CountType)Enum.Parse(typeof(CountType), n)));
|
||||||
countType.BindTo(typeDropdown.Current);
|
countType.BindTo(typeDropdown.Current);
|
||||||
countType.ValueChanged += v => beginStep(lastStep)();
|
countType.ValueChanged += v => beginStep(lastStep)();
|
||||||
|
|
||||||
AddStep("1 -> 4 | 1 sec", beginStep(() => counter.CountTo(1).CountTo(4, 1000)));
|
AddStep("1 -> 4 | 1 sec", beginStep(() => counter.CountTo(1).CountTo(4, 1000)));
|
||||||
AddStep("1 -> 4 | 3 sec", beginStep(() => counter.CountTo(1).CountTo(4, 3000)));
|
AddStep("1 -> 4 | 3 sec", beginStep(() => counter.CountTo(1).CountTo(4, 3000)));
|
||||||
AddStep("4 -> 1 | 1 sec", beginStep(() => counter.CountTo(4).CountTo(1, 1000)));
|
AddStep("4 -> 1 | 1 sec", beginStep(() => counter.CountTo(4).CountTo(1, 1000)));
|
||||||
AddStep("4 -> 1 | 3 sec", beginStep(() => counter.CountTo(4).CountTo(1, 3000)));
|
AddStep("4 -> 1 | 3 sec", beginStep(() => counter.CountTo(4).CountTo(1, 3000)));
|
||||||
AddStep("1 -> 4 -> 1 | 6 sec", beginStep(() => counter.CountTo(1).CountTo(4, 3000).Then().CountTo(1, 3000)));
|
AddStep("1 -> 4 -> 1 | 6 sec", beginStep(() => counter.CountTo(1).CountTo(4, 3000).Then().CountTo(1, 3000)));
|
||||||
AddStep("1 -> 4 -> 1 | 2 sec", beginStep(() => counter.CountTo(1).CountTo(4, 1000).Then().CountTo(1, 1000)));
|
AddStep("1 -> 4 -> 1 | 2 sec", beginStep(() => counter.CountTo(1).CountTo(4, 1000).Then().CountTo(1, 1000)));
|
||||||
AddStep("1 -> 100 | 5 sec | OutQuint", beginStep(() => counter.CountTo(1).CountTo(100, 5000, Easing.OutQuint)));
|
AddStep("1 -> 100 | 5 sec | OutQuint", beginStep(() => counter.CountTo(1).CountTo(100, 5000, Easing.OutQuint)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action lastStep;
|
private Action lastStep;
|
||||||
private Action beginStep(Action stepAction) => () =>
|
private Action beginStep(Action stepAction) => () =>
|
||||||
{
|
{
|
||||||
lastStep = stepAction;
|
lastStep = stepAction;
|
||||||
stepAction?.Invoke();
|
stepAction?.Invoke();
|
||||||
};
|
};
|
||||||
|
|
||||||
private string createResult(double value)
|
private string createResult(double value)
|
||||||
{
|
{
|
||||||
switch (countType.Value)
|
switch (countType.Value)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case CountType.AsDouble:
|
case CountType.AsDouble:
|
||||||
return value.ToString(CultureInfo.InvariantCulture);
|
return value.ToString(CultureInfo.InvariantCulture);
|
||||||
case CountType.AsInteger:
|
case CountType.AsInteger:
|
||||||
return ((int)value).ToString();
|
return ((int)value).ToString();
|
||||||
case CountType.AsIntegerCeiling:
|
case CountType.AsIntegerCeiling:
|
||||||
return ((int)Math.Ceiling(value)).ToString();
|
return ((int)Math.Ceiling(value)).ToString();
|
||||||
case CountType.AsDouble2:
|
case CountType.AsDouble2:
|
||||||
return Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
return Math.Round(value, 2).ToString(CultureInfo.InvariantCulture);
|
||||||
case CountType.AsDouble4:
|
case CountType.AsDouble4:
|
||||||
return Math.Round(value, 4).ToString(CultureInfo.InvariantCulture);
|
return Math.Round(value, 4).ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum CountType
|
private enum CountType
|
||||||
{
|
{
|
||||||
AsInteger,
|
AsInteger,
|
||||||
AsIntegerCeiling,
|
AsIntegerCeiling,
|
||||||
AsDouble,
|
AsDouble,
|
||||||
AsDouble2,
|
AsDouble2,
|
||||||
AsDouble4,
|
AsDouble4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestTextCounter : Counter
|
public class TestTextCounter : Counter
|
||||||
{
|
{
|
||||||
private readonly Func<double, string> resultFunction;
|
private readonly Func<double, string> resultFunction;
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
|
|
||||||
public TestTextCounter(Func<double, string> resultFunction)
|
public TestTextCounter(Func<double, string> resultFunction)
|
||||||
{
|
{
|
||||||
this.resultFunction = resultFunction;
|
this.resultFunction = resultFunction;
|
||||||
AddInternal(text = new SpriteText { TextSize = 24 });
|
AddInternal(text = new SpriteText { TextSize = 24 });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnCountChanged(double count) => text.Text = resultFunction(count);
|
protected override void OnCountChanged(double count) => text.Text = resultFunction(count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +1,93 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseDelayedLoad : TestCase
|
public class TestCaseDelayedLoad : TestCase
|
||||||
{
|
{
|
||||||
private const int panel_count = 2048;
|
private const int panel_count = 2048;
|
||||||
|
|
||||||
public TestCaseDelayedLoad()
|
public TestCaseDelayedLoad()
|
||||||
{
|
{
|
||||||
FillFlowContainerNoInput flow;
|
FillFlowContainerNoInput flow;
|
||||||
ScrollContainer scroll;
|
ScrollContainer scroll;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
scroll = new ScrollContainer
|
scroll = new ScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainerNoInput
|
flow = new FillFlowContainerNoInput
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 1; i < panel_count; i++)
|
for (int i = 1; i < panel_count; i++)
|
||||||
flow.Add(new Container
|
flow.Add(new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(128),
|
Size = new Vector2(128),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new DelayedLoadWrapper(new Container
|
new DelayedLoadWrapper(new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TestBox{ RelativeSizeAxes = Axes.Both }
|
new TestBox{ RelativeSizeAxes = Axes.Both }
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new SpriteText { Text = i.ToString() },
|
new SpriteText { Text = i.ToString() },
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var childrenWithAvatarsLoaded = flow.Children.Where(c => c.Children.OfType<DelayedLoadWrapper>().First().Content?.IsLoaded ?? false);
|
var childrenWithAvatarsLoaded = flow.Children.Where(c => c.Children.OfType<DelayedLoadWrapper>().First().Content?.IsLoaded ?? false);
|
||||||
|
|
||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
AddStep("scroll down", () => scroll.ScrollToEnd());
|
AddStep("scroll down", () => scroll.ScrollToEnd());
|
||||||
AddWaitStep(10);
|
AddWaitStep(10);
|
||||||
AddAssert("some loaded", () => childrenWithAvatarsLoaded.Count() > 5);
|
AddAssert("some loaded", () => childrenWithAvatarsLoaded.Count() > 5);
|
||||||
AddAssert("not too many loaded", () => childrenWithAvatarsLoaded.Count() < panel_count / 4);
|
AddAssert("not too many loaded", () => childrenWithAvatarsLoaded.Count() < panel_count / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FillFlowContainerNoInput : FillFlowContainer<Container>
|
private class FillFlowContainerNoInput : FillFlowContainer<Container>
|
||||||
{
|
{
|
||||||
public override bool HandleKeyboardInput => false;
|
public override bool HandleKeyboardInput => false;
|
||||||
public override bool HandleMouseInput => false;
|
public override bool HandleMouseInput => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestBox : Container
|
public class TestBox : Container
|
||||||
{
|
{
|
||||||
public TestBox()
|
public TestBox()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Child = new SpriteText
|
Child = new SpriteText
|
||||||
{
|
{
|
||||||
Colour = Color4.Yellow,
|
Colour = Color4.Yellow,
|
||||||
Text = @"loaded",
|
Text = @"loaded",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,61 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseDrawSizePreservingFillContainer : TestCase
|
public class TestCaseDrawSizePreservingFillContainer : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseDrawSizePreservingFillContainer()
|
public TestCaseDrawSizePreservingFillContainer()
|
||||||
{
|
{
|
||||||
DrawSizePreservingFillContainer fillContainer;
|
DrawSizePreservingFillContainer fillContainer;
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(500),
|
Size = new Vector2(500),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding(10),
|
Padding = new MarginPadding(10),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
fillContainer = new DrawSizePreservingFillContainer
|
fillContainer = new DrawSizePreservingFillContainer
|
||||||
{
|
{
|
||||||
Child = new TestCaseSizing(),
|
Child = new TestCaseSizing(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddStep("Strategy: Minimum", () => fillContainer.Strategy = DrawSizePreservationStrategy.Minimum);
|
AddStep("Strategy: Minimum", () => fillContainer.Strategy = DrawSizePreservationStrategy.Minimum);
|
||||||
AddStep("Strategy: Maximum", () => fillContainer.Strategy = DrawSizePreservationStrategy.Maximum);
|
AddStep("Strategy: Maximum", () => fillContainer.Strategy = DrawSizePreservationStrategy.Maximum);
|
||||||
AddStep("Strategy: Average", () => fillContainer.Strategy = DrawSizePreservationStrategy.Average);
|
AddStep("Strategy: Average", () => fillContainer.Strategy = DrawSizePreservationStrategy.Average);
|
||||||
AddStep("Strategy: Separate", () => fillContainer.Strategy = DrawSizePreservationStrategy.Separate);
|
AddStep("Strategy: Separate", () => fillContainer.Strategy = DrawSizePreservationStrategy.Separate);
|
||||||
|
|
||||||
AddSliderStep("Width", 50, 650, 500, v => Child.Width = v);
|
AddSliderStep("Width", 50, 650, 500, v => Child.Width = v);
|
||||||
AddSliderStep("Height", 50, 650, 500, v => Child.Height = v);
|
AddSliderStep("Height", 50, 650, 500, v => Child.Height = v);
|
||||||
|
|
||||||
AddStep("Override Size to 1x1", () => Child.Size = Vector2.One);
|
AddStep("Override Size to 1x1", () => Child.Size = Vector2.One);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,128 +1,128 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseDrawablePath : GridTestCase
|
public class TestCaseDrawablePath : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseDrawablePath() : base(2, 2)
|
public TestCaseDrawablePath() : base(2, 2)
|
||||||
{
|
{
|
||||||
const int width = 20;
|
const int width = 20;
|
||||||
Texture gradientTexture = new Texture(width, 1, true);
|
Texture gradientTexture = new Texture(width, 1, true);
|
||||||
byte[] data = new byte[width * 4];
|
byte[] data = new byte[width * 4];
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < width; ++i)
|
||||||
{
|
{
|
||||||
float brightness = (float)i / (width - 1);
|
float brightness = (float)i / (width - 1);
|
||||||
int index = i * 4;
|
int index = i * 4;
|
||||||
data[index + 0] = (byte)(brightness * 255);
|
data[index + 0] = (byte)(brightness * 255);
|
||||||
data[index + 1] = (byte)(brightness * 255);
|
data[index + 1] = (byte)(brightness * 255);
|
||||||
data[index + 2] = (byte)(brightness * 255);
|
data[index + 2] = (byte)(brightness * 255);
|
||||||
data[index + 3] = 255;
|
data[index + 3] = 255;
|
||||||
}
|
}
|
||||||
gradientTexture.SetData(new TextureUpload(data));
|
gradientTexture.SetData(new TextureUpload(data));
|
||||||
|
|
||||||
Cell(0).AddRange(new[]
|
Cell(0).AddRange(new[]
|
||||||
{
|
{
|
||||||
createLabel("Simple path"),
|
createLabel("Simple path"),
|
||||||
new Path
|
new Path
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Positions = new List<Vector2> { Vector2.One * 50, Vector2.One * 100 },
|
Positions = new List<Vector2> { Vector2.One * 50, Vector2.One * 100 },
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.Green,
|
Colour = Color4.Green,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(1).AddRange(new[]
|
Cell(1).AddRange(new[]
|
||||||
{
|
{
|
||||||
createLabel("Curved path"),
|
createLabel("Curved path"),
|
||||||
new Path
|
new Path
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Positions = new List<Vector2>
|
Positions = new List<Vector2>
|
||||||
{
|
{
|
||||||
new Vector2(50, 50),
|
new Vector2(50, 50),
|
||||||
new Vector2(50, 250),
|
new Vector2(50, 250),
|
||||||
new Vector2(250, 250),
|
new Vector2(250, 250),
|
||||||
new Vector2(250, 50),
|
new Vector2(250, 50),
|
||||||
new Vector2(50, 50),
|
new Vector2(50, 50),
|
||||||
},
|
},
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(2).AddRange(new[]
|
Cell(2).AddRange(new[]
|
||||||
{
|
{
|
||||||
createLabel("Self-overlapping path"),
|
createLabel("Self-overlapping path"),
|
||||||
new Path
|
new Path
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Positions = new List<Vector2>
|
Positions = new List<Vector2>
|
||||||
{
|
{
|
||||||
new Vector2(50, 50),
|
new Vector2(50, 50),
|
||||||
new Vector2(50, 250),
|
new Vector2(50, 250),
|
||||||
new Vector2(250, 250),
|
new Vector2(250, 250),
|
||||||
new Vector2(250, 150),
|
new Vector2(250, 150),
|
||||||
new Vector2(20, 150),
|
new Vector2(20, 150),
|
||||||
},
|
},
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(3).AddRange(new[]
|
Cell(3).AddRange(new[]
|
||||||
{
|
{
|
||||||
createLabel("Draw something ;)"),
|
createLabel("Draw something ;)"),
|
||||||
new UserDrawnPath
|
new UserDrawnPath
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable createLabel(string text) => new SpriteText
|
private Drawable createLabel(string text) => new SpriteText
|
||||||
{
|
{
|
||||||
Text = text,
|
Text = text,
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
};
|
};
|
||||||
|
|
||||||
private class UserDrawnPath : Path
|
private class UserDrawnPath : Path
|
||||||
{
|
{
|
||||||
private Vector2 oldPos;
|
private Vector2 oldPos;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
protected override bool OnDragStart(InputState state)
|
||||||
{
|
{
|
||||||
AddVertex(state.Mouse.Position);
|
AddVertex(state.Mouse.Position);
|
||||||
oldPos = state.Mouse.Position;
|
oldPos = state.Mouse.Position;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
Vector2 pos = state.Mouse.Position;
|
Vector2 pos = state.Mouse.Position;
|
||||||
if ((pos - oldPos).Length > 10)
|
if ((pos - oldPos).Length > 10)
|
||||||
{
|
{
|
||||||
AddVertex(pos);
|
AddVertex(pos);
|
||||||
oldPos = pos;
|
oldPos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnDrag(state);
|
return base.OnDrag(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,105 +1,105 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseDropdownBox : TestCase
|
public class TestCaseDropdownBox : TestCase
|
||||||
{
|
{
|
||||||
private const int items_to_add = 10;
|
private const int items_to_add = 10;
|
||||||
|
|
||||||
public TestCaseDropdownBox()
|
public TestCaseDropdownBox()
|
||||||
{
|
{
|
||||||
StyledDropdown styledDropdown, styledDropdownMenu2;
|
StyledDropdown styledDropdown, styledDropdownMenu2;
|
||||||
|
|
||||||
var testItems = new string[10];
|
var testItems = new string[10];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < items_to_add)
|
while (i < items_to_add)
|
||||||
testItems[i] = @"test " + i++;
|
testItems[i] = @"test " + i++;
|
||||||
|
|
||||||
Add(styledDropdown = new StyledDropdown
|
Add(styledDropdown = new StyledDropdown
|
||||||
{
|
{
|
||||||
Width = 150,
|
Width = 150,
|
||||||
Position = new Vector2(200, 70),
|
Position = new Vector2(200, 70),
|
||||||
Items = testItems.Select(item => new KeyValuePair<string, string>(item, item)),
|
Items = testItems.Select(item => new KeyValuePair<string, string>(item, item)),
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(styledDropdownMenu2 = new StyledDropdown
|
Add(styledDropdownMenu2 = new StyledDropdown
|
||||||
{
|
{
|
||||||
Width = 150,
|
Width = 150,
|
||||||
Position = new Vector2(400, 70),
|
Position = new Vector2(400, 70),
|
||||||
Items = testItems.Select(item => new KeyValuePair<string, string>(item, item)),
|
Items = testItems.Select(item => new KeyValuePair<string, string>(item, item)),
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("click dropdown1", () => toggleDropdownViaClick(styledDropdown));
|
AddStep("click dropdown1", () => toggleDropdownViaClick(styledDropdown));
|
||||||
AddAssert("dropdown is open", () => styledDropdown.Menu.State == MenuState.Open);
|
AddAssert("dropdown is open", () => styledDropdown.Menu.State == MenuState.Open);
|
||||||
|
|
||||||
AddRepeatStep("add item", () => styledDropdown.AddDropdownItem(@"test " + i, @"test " + i++), items_to_add);
|
AddRepeatStep("add item", () => styledDropdown.AddDropdownItem(@"test " + i, @"test " + i++), items_to_add);
|
||||||
AddAssert("item count is correct", () => styledDropdown.Items.Count() == items_to_add * 2);
|
AddAssert("item count is correct", () => styledDropdown.Items.Count() == items_to_add * 2);
|
||||||
|
|
||||||
AddStep("click item 13", () => styledDropdown.SelectItem(styledDropdown.Menu.Items[13]));
|
AddStep("click item 13", () => styledDropdown.SelectItem(styledDropdown.Menu.Items[13]));
|
||||||
|
|
||||||
AddAssert("dropdown1 is closed", () => styledDropdown.Menu.State == MenuState.Closed);
|
AddAssert("dropdown1 is closed", () => styledDropdown.Menu.State == MenuState.Closed);
|
||||||
AddAssert("item 13 is selected", () => styledDropdown.Current == styledDropdown.Items.ElementAt(13).Value);
|
AddAssert("item 13 is selected", () => styledDropdown.Current == styledDropdown.Items.ElementAt(13).Value);
|
||||||
|
|
||||||
AddStep("select item 15", () => styledDropdown.Current.Value = styledDropdown.Items.ElementAt(15).Value);
|
AddStep("select item 15", () => styledDropdown.Current.Value = styledDropdown.Items.ElementAt(15).Value);
|
||||||
AddAssert("item 15 is selected", () => styledDropdown.Current == styledDropdown.Items.ElementAt(15).Value);
|
AddAssert("item 15 is selected", () => styledDropdown.Current == styledDropdown.Items.ElementAt(15).Value);
|
||||||
|
|
||||||
AddStep("click dropdown1", () => toggleDropdownViaClick(styledDropdown));
|
AddStep("click dropdown1", () => toggleDropdownViaClick(styledDropdown));
|
||||||
AddAssert("dropdown1 is open", () => styledDropdown.Menu.State == MenuState.Open);
|
AddAssert("dropdown1 is open", () => styledDropdown.Menu.State == MenuState.Open);
|
||||||
|
|
||||||
AddStep("click dropdown2", () => toggleDropdownViaClick(styledDropdownMenu2));
|
AddStep("click dropdown2", () => toggleDropdownViaClick(styledDropdownMenu2));
|
||||||
|
|
||||||
AddAssert("dropdown1 is closed", () => styledDropdown.Menu.State == MenuState.Closed);
|
AddAssert("dropdown1 is closed", () => styledDropdown.Menu.State == MenuState.Closed);
|
||||||
AddAssert("dropdown2 is open", () => styledDropdownMenu2.Menu.State == MenuState.Open);
|
AddAssert("dropdown2 is open", () => styledDropdownMenu2.Menu.State == MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleDropdownViaClick(StyledDropdown dropdown) => dropdown.Children.First().TriggerOnClick();
|
private void toggleDropdownViaClick(StyledDropdown dropdown) => dropdown.Children.First().TriggerOnClick();
|
||||||
|
|
||||||
private class StyledDropdown : BasicDropdown<string>
|
private class StyledDropdown : BasicDropdown<string>
|
||||||
{
|
{
|
||||||
public new DropdownMenu Menu => base.Menu;
|
public new DropdownMenu Menu => base.Menu;
|
||||||
|
|
||||||
protected override DropdownMenu CreateMenu() => new StyledDropdownMenu();
|
protected override DropdownMenu CreateMenu() => new StyledDropdownMenu();
|
||||||
|
|
||||||
protected override DropdownHeader CreateHeader() => new StyledDropdownHeader();
|
protected override DropdownHeader CreateHeader() => new StyledDropdownHeader();
|
||||||
|
|
||||||
public void SelectItem(MenuItem item) => ((StyledDropdownMenu)Menu).SelectItem(item);
|
public void SelectItem(MenuItem item) => ((StyledDropdownMenu)Menu).SelectItem(item);
|
||||||
|
|
||||||
private class StyledDropdownMenu : DropdownMenu
|
private class StyledDropdownMenu : DropdownMenu
|
||||||
{
|
{
|
||||||
public void SelectItem(MenuItem item) => Children.FirstOrDefault(c => c.Item == item)?.TriggerOnClick();
|
public void SelectItem(MenuItem item) => Children.FirstOrDefault(c => c.Item == item)?.TriggerOnClick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledDropdownHeader : DropdownHeader
|
private class StyledDropdownHeader : DropdownHeader
|
||||||
{
|
{
|
||||||
private readonly SpriteText label;
|
private readonly SpriteText label;
|
||||||
|
|
||||||
protected internal override string Label
|
protected internal override string Label
|
||||||
{
|
{
|
||||||
get { return label.Text; }
|
get { return label.Text; }
|
||||||
set { label.Text = value; }
|
set { label.Text = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public StyledDropdownHeader()
|
public StyledDropdownHeader()
|
||||||
{
|
{
|
||||||
Foreground.Padding = new MarginPadding(4);
|
Foreground.Padding = new MarginPadding(4);
|
||||||
BackgroundColour = new Color4(255, 255, 255, 100);
|
BackgroundColour = new Color4(255, 255, 255, 100);
|
||||||
BackgroundColourHover = Color4.HotPink;
|
BackgroundColourHover = Color4.HotPink;
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
label = new SpriteText(),
|
label = new SpriteText(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +1,83 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("changing depth of child dynamically")]
|
[System.ComponentModel.Description("changing depth of child dynamically")]
|
||||||
public class TestCaseDynamicDepth : TestCase
|
public class TestCaseDynamicDepth : TestCase
|
||||||
{
|
{
|
||||||
private void addDepthSteps(DepthBox box, Container container)
|
private void addDepthSteps(DepthBox box, Container container)
|
||||||
{
|
{
|
||||||
AddStep($@"bring forward {box.Name}", () => container.ChangeChildDepth(box, box.Depth - 1));
|
AddStep($@"bring forward {box.Name}", () => container.ChangeChildDepth(box, box.Depth - 1));
|
||||||
AddStep($@"send backward {box.Name}", () => container.ChangeChildDepth(box, box.Depth + 1));
|
AddStep($@"send backward {box.Name}", () => container.ChangeChildDepth(box, box.Depth + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseDynamicDepth()
|
public TestCaseDynamicDepth()
|
||||||
{
|
{
|
||||||
DepthBox red, blue, green, purple;
|
DepthBox red, blue, green, purple;
|
||||||
Container container;
|
Container container;
|
||||||
|
|
||||||
AddRange(new[]
|
AddRange(new[]
|
||||||
{
|
{
|
||||||
container = new Container
|
container = new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(340),
|
Size = new Vector2(340),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
red = new DepthBox(Color4.Red, Anchor.TopLeft) { Name = "red" },
|
red = new DepthBox(Color4.Red, Anchor.TopLeft) { Name = "red" },
|
||||||
blue = new DepthBox(Color4.Blue, Anchor.TopRight) { Name = "blue" },
|
blue = new DepthBox(Color4.Blue, Anchor.TopRight) { Name = "blue" },
|
||||||
green = new DepthBox(Color4.Green, Anchor.BottomRight) { Name = "green" },
|
green = new DepthBox(Color4.Green, Anchor.BottomRight) { Name = "green" },
|
||||||
purple = new DepthBox(Color4.Purple, Anchor.BottomLeft) { Name = "purple" },
|
purple = new DepthBox(Color4.Purple, Anchor.BottomLeft) { Name = "purple" },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addDepthSteps(red, container);
|
addDepthSteps(red, container);
|
||||||
addDepthSteps(blue, container);
|
addDepthSteps(blue, container);
|
||||||
addDepthSteps(green, container);
|
addDepthSteps(green, container);
|
||||||
addDepthSteps(purple, container);
|
addDepthSteps(purple, container);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DepthBox : Container
|
private class DepthBox : Container
|
||||||
{
|
{
|
||||||
private readonly SpriteText depthText;
|
private readonly SpriteText depthText;
|
||||||
|
|
||||||
public DepthBox(Color4 colour, Anchor anchor)
|
public DepthBox(Color4 colour, Anchor anchor)
|
||||||
{
|
{
|
||||||
Size = new Vector2(240);
|
Size = new Vector2(240);
|
||||||
Anchor = Origin = anchor;
|
Anchor = Origin = anchor;
|
||||||
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colour,
|
Colour = colour,
|
||||||
},
|
},
|
||||||
depthText = new SpriteText
|
depthText = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = anchor,
|
Anchor = anchor,
|
||||||
Origin = anchor,
|
Origin = anchor,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
depthText.Text = $@"Depth: {Depth}";
|
depthText.Text = $@"Depth: {Depth}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,238 +1,238 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Colour;
|
using osu.Framework.Graphics.Colour;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("implementing the IEffect interface")]
|
[System.ComponentModel.Description("implementing the IEffect interface")]
|
||||||
public class TestCaseEffects : TestCase
|
public class TestCaseEffects : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseEffects()
|
public TestCaseEffects()
|
||||||
{
|
{
|
||||||
var effect = new EdgeEffect
|
var effect = new EdgeEffect
|
||||||
{
|
{
|
||||||
CornerRadius = 3f,
|
CornerRadius = 3f,
|
||||||
Parameters = new EdgeEffectParameters
|
Parameters = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = Color4.LightBlue,
|
Colour = Color4.LightBlue,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
Radius = 5f,
|
Radius = 5f,
|
||||||
Type = EdgeEffectType.Glow
|
Type = EdgeEffectType.Glow
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
Position = new Vector2(10f, 10f),
|
Position = new Vector2(10f, 10f),
|
||||||
Spacing = new Vector2(25f, 25f),
|
Spacing = new Vector2(25f, 25f),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Blur Test",
|
Text = "Blur Test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(new BlurEffect
|
}.WithEffect(new BlurEffect
|
||||||
{
|
{
|
||||||
Sigma = new Vector2(2f, 0f),
|
Sigma = new Vector2(2f, 0f),
|
||||||
Strength = 2f,
|
Strength = 2f,
|
||||||
Rotation = 45f,
|
Rotation = 45f,
|
||||||
}),
|
}),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "EdgeEffect Test",
|
Text = "EdgeEffect Test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(new EdgeEffect
|
}.WithEffect(new EdgeEffect
|
||||||
{
|
{
|
||||||
CornerRadius = 3f,
|
CornerRadius = 3f,
|
||||||
Parameters = new EdgeEffectParameters
|
Parameters = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = Color4.Yellow,
|
Colour = Color4.Yellow,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
Radius = 5f,
|
Radius = 5f,
|
||||||
Type = EdgeEffectType.Shadow
|
Type = EdgeEffectType.Shadow
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Repeated usage of same effect test",
|
Text = "Repeated usage of same effect test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(effect),
|
}.WithEffect(effect),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Repeated usage of same effect test",
|
Text = "Repeated usage of same effect test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(effect),
|
}.WithEffect(effect),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Repeated usage of same effect test",
|
Text = "Repeated usage of same effect test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(effect),
|
}.WithEffect(effect),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Multiple effects Test",
|
Text = "Multiple effects Test",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(new BlurEffect
|
}.WithEffect(new BlurEffect
|
||||||
{
|
{
|
||||||
Sigma = new Vector2(2f, 2f),
|
Sigma = new Vector2(2f, 2f),
|
||||||
Strength = 2f
|
Strength = 2f
|
||||||
}).WithEffect(new EdgeEffect
|
}).WithEffect(new EdgeEffect
|
||||||
{
|
{
|
||||||
CornerRadius = 3f,
|
CornerRadius = 3f,
|
||||||
Parameters = new EdgeEffectParameters
|
Parameters = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = Color4.Yellow,
|
Colour = Color4.Yellow,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
Radius = 5f,
|
Radius = 5f,
|
||||||
Type = EdgeEffectType.Shadow
|
Type = EdgeEffectType.Shadow
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.CornflowerBlue,
|
Colour = Color4.CornflowerBlue,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Outlined Text",
|
Text = "Outlined Text",
|
||||||
TextSize = 32f
|
TextSize = 32f
|
||||||
}.WithEffect(new OutlineEffect
|
}.WithEffect(new OutlineEffect
|
||||||
{
|
{
|
||||||
BlurSigma = new Vector2(3f),
|
BlurSigma = new Vector2(3f),
|
||||||
Strength = 3f,
|
Strength = 3f,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.CornflowerBlue,
|
Colour = Color4.CornflowerBlue,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Glowing Text",
|
Text = "Glowing Text",
|
||||||
TextSize = 32f,
|
TextSize = 32f,
|
||||||
}.WithEffect(new GlowEffect
|
}.WithEffect(new GlowEffect
|
||||||
{
|
{
|
||||||
BlurSigma = new Vector2(3f),
|
BlurSigma = new Vector2(3f),
|
||||||
Strength = 3f,
|
Strength = 3f,
|
||||||
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
Size = new Vector2(150, 40),
|
Size = new Vector2(150, 40),
|
||||||
}.WithEffect(new GlowEffect
|
}.WithEffect(new GlowEffect
|
||||||
{
|
{
|
||||||
BlurSigma = new Vector2(3f),
|
BlurSigma = new Vector2(3f),
|
||||||
Strength = 3f,
|
Strength = 3f,
|
||||||
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
}),
|
}),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Absolute Size",
|
Text = "Absolute Size",
|
||||||
TextSize = 32f,
|
TextSize = 32f,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
Shadow = true,
|
Shadow = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(1.1f, 1.1f),
|
Size = new Vector2(1.1f, 1.1f),
|
||||||
}.WithEffect(new GlowEffect
|
}.WithEffect(new GlowEffect
|
||||||
{
|
{
|
||||||
BlurSigma = new Vector2(3f),
|
BlurSigma = new Vector2(3f),
|
||||||
Strength = 3f,
|
Strength = 3f,
|
||||||
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
}),
|
}),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Relative Size",
|
Text = "Relative Size",
|
||||||
TextSize = 32f,
|
TextSize = 32f,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
Shadow = true,
|
Shadow = true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(1.1f, 1.1f),
|
Size = new Vector2(1.1f, 1.1f),
|
||||||
Rotation = 10,
|
Rotation = 10,
|
||||||
}.WithEffect(new GlowEffect
|
}.WithEffect(new GlowEffect
|
||||||
{
|
{
|
||||||
BlurSigma = new Vector2(3f),
|
BlurSigma = new Vector2(3f),
|
||||||
Strength = 3f,
|
Strength = 3f,
|
||||||
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
Colour = ColourInfo.GradientHorizontal(new Color4(1.2f, 0, 0, 1f), new Color4(0, 1f, 0, 1f)),
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
}),
|
}),
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = "Rotation",
|
Text = "Rotation",
|
||||||
TextSize = 32f,
|
TextSize = 32f,
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
Shadow = true,
|
Shadow = true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,420 +1,420 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseFillFlowContainer : TestCase
|
public class TestCaseFillFlowContainer : TestCase
|
||||||
{
|
{
|
||||||
private FillDirectionDropdown selectionDropdown;
|
private FillDirectionDropdown selectionDropdown;
|
||||||
|
|
||||||
private Anchor childAnchor = Anchor.TopLeft;
|
private Anchor childAnchor = Anchor.TopLeft;
|
||||||
private AnchorDropdown anchorDropdown;
|
private AnchorDropdown anchorDropdown;
|
||||||
|
|
||||||
private Anchor childOrigin = Anchor.TopLeft;
|
private Anchor childOrigin = Anchor.TopLeft;
|
||||||
private AnchorDropdown originDropdown;
|
private AnchorDropdown originDropdown;
|
||||||
|
|
||||||
private FillFlowContainer fillContainer;
|
private FillFlowContainer fillContainer;
|
||||||
private ScheduledDelegate scheduledAdder;
|
private ScheduledDelegate scheduledAdder;
|
||||||
private bool doNotAddChildren;
|
private bool doNotAddChildren;
|
||||||
|
|
||||||
public TestCaseFillFlowContainer()
|
public TestCaseFillFlowContainer()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset()
|
private void reset()
|
||||||
{
|
{
|
||||||
doNotAddChildren = false;
|
doNotAddChildren = false;
|
||||||
scheduledAdder?.Cancel();
|
scheduledAdder?.Cancel();
|
||||||
|
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Depth = float.MinValue,
|
Depth = float.MinValue,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = @"Fill mode" },
|
new SpriteText { Text = @"Fill mode" },
|
||||||
selectionDropdown = new FillDirectionDropdown
|
selectionDropdown = new FillDirectionDropdown
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Items = Enum.GetValues(typeof(FlowTestCase)).Cast<FlowTestCase>()
|
Items = Enum.GetValues(typeof(FlowTestCase)).Cast<FlowTestCase>()
|
||||||
.Select(value => new KeyValuePair<string, FlowTestCase>(value.ToString(), value)),
|
.Select(value => new KeyValuePair<string, FlowTestCase>(value.ToString(), value)),
|
||||||
},
|
},
|
||||||
new SpriteText { Text = @"Child anchor" },
|
new SpriteText { Text = @"Child anchor" },
|
||||||
anchorDropdown = new AnchorDropdown
|
anchorDropdown = new AnchorDropdown
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Items = new[]
|
Items = new[]
|
||||||
{
|
{
|
||||||
Anchor.TopLeft,
|
Anchor.TopLeft,
|
||||||
Anchor.TopCentre,
|
Anchor.TopCentre,
|
||||||
Anchor.TopRight,
|
Anchor.TopRight,
|
||||||
Anchor.CentreLeft,
|
Anchor.CentreLeft,
|
||||||
Anchor.Centre,
|
Anchor.Centre,
|
||||||
Anchor.CentreRight,
|
Anchor.CentreRight,
|
||||||
Anchor.BottomLeft,
|
Anchor.BottomLeft,
|
||||||
Anchor.BottomCentre,
|
Anchor.BottomCentre,
|
||||||
Anchor.BottomRight,
|
Anchor.BottomRight,
|
||||||
}.Select(anchor => new KeyValuePair<string, Anchor>(anchor.ToString(), anchor)),
|
}.Select(anchor => new KeyValuePair<string, Anchor>(anchor.ToString(), anchor)),
|
||||||
},
|
},
|
||||||
new SpriteText { Text = @"Child origin" },
|
new SpriteText { Text = @"Child origin" },
|
||||||
originDropdown = new AnchorDropdown
|
originDropdown = new AnchorDropdown
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Items = new[]
|
Items = new[]
|
||||||
{
|
{
|
||||||
Anchor.TopLeft,
|
Anchor.TopLeft,
|
||||||
Anchor.TopCentre,
|
Anchor.TopCentre,
|
||||||
Anchor.TopRight,
|
Anchor.TopRight,
|
||||||
Anchor.CentreLeft,
|
Anchor.CentreLeft,
|
||||||
Anchor.Centre,
|
Anchor.Centre,
|
||||||
Anchor.CentreRight,
|
Anchor.CentreRight,
|
||||||
Anchor.BottomLeft,
|
Anchor.BottomLeft,
|
||||||
Anchor.BottomCentre,
|
Anchor.BottomCentre,
|
||||||
Anchor.BottomRight,
|
Anchor.BottomRight,
|
||||||
}.Select(anchor => new KeyValuePair<string, Anchor>(anchor.ToString(), anchor)),
|
}.Select(anchor => new KeyValuePair<string, Anchor>(anchor.ToString(), anchor)),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
selectionDropdown.Current.ValueChanged += changeTest;
|
selectionDropdown.Current.ValueChanged += changeTest;
|
||||||
buildTest();
|
buildTest();
|
||||||
selectionDropdown.Current.Value = FlowTestCase.Full;
|
selectionDropdown.Current.Value = FlowTestCase.Full;
|
||||||
changeTest(FlowTestCase.Full);
|
changeTest(FlowTestCase.Full);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (childAnchor != anchorDropdown.Current)
|
if (childAnchor != anchorDropdown.Current)
|
||||||
{
|
{
|
||||||
childAnchor = anchorDropdown.Current;
|
childAnchor = anchorDropdown.Current;
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.Anchor = childAnchor;
|
child.Anchor = childAnchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childOrigin != originDropdown.Current)
|
if (childOrigin != originDropdown.Current)
|
||||||
{
|
{
|
||||||
childOrigin = originDropdown.Current;
|
childOrigin = originDropdown.Current;
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.Origin = childOrigin;
|
child.Origin = childOrigin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeTest(FlowTestCase testCase)
|
private void changeTest(FlowTestCase testCase)
|
||||||
{
|
{
|
||||||
var method =
|
var method =
|
||||||
GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(m => m.GetCustomAttribute<FlowTestCaseAttribute>()?.TestCase == testCase);
|
GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(m => m.GetCustomAttribute<FlowTestCaseAttribute>()?.TestCase == testCase);
|
||||||
if (method != null)
|
if (method != null)
|
||||||
method.Invoke(this, new object[0]);
|
method.Invoke(this, new object[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildTest()
|
private void buildTest()
|
||||||
{
|
{
|
||||||
Add(new Container
|
Add(new Container
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(25f),
|
Padding = new MarginPadding(25f),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
fillContainer = new FillFlowContainer
|
fillContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.None,
|
AutoSizeAxes = Axes.None,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Size = new Vector2(3, 1),
|
Size = new Vector2(3, 1),
|
||||||
Colour = Color4.HotPink,
|
Colour = Color4.HotPink,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Size = new Vector2(3, 1),
|
Size = new Vector2(3, 1),
|
||||||
Colour = Color4.HotPink,
|
Colour = Color4.HotPink,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Size = new Vector2(1, 3),
|
Size = new Vector2(1, 3),
|
||||||
Colour = Color4.HotPink,
|
Colour = Color4.HotPink,
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Size = new Vector2(1, 3),
|
Size = new Vector2(1, 3),
|
||||||
Colour = Color4.HotPink,
|
Colour = Color4.HotPink,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddToggleStep("Rotate Container", state => { fillContainer.RotateTo(state ? 45f : 0, 1000); });
|
AddToggleStep("Rotate Container", state => { fillContainer.RotateTo(state ? 45f : 0, 1000); });
|
||||||
AddToggleStep("Scale Container", state => { fillContainer.ScaleTo(state ? 1.2f : 1f, 1000); });
|
AddToggleStep("Scale Container", state => { fillContainer.ScaleTo(state ? 1.2f : 1f, 1000); });
|
||||||
AddToggleStep("Shear Container", state => { fillContainer.Shear = state ? new Vector2(0.5f, 0f) : new Vector2(0f, 0f); });
|
AddToggleStep("Shear Container", state => { fillContainer.Shear = state ? new Vector2(0.5f, 0f) : new Vector2(0f, 0f); });
|
||||||
AddToggleStep("Center Container Anchor", state => { fillContainer.Anchor = state ? Anchor.Centre : Anchor.TopLeft; });
|
AddToggleStep("Center Container Anchor", state => { fillContainer.Anchor = state ? Anchor.Centre : Anchor.TopLeft; });
|
||||||
AddToggleStep("Center Container Origin", state => { fillContainer.Origin = state ? Anchor.Centre : Anchor.TopLeft; });
|
AddToggleStep("Center Container Origin", state => { fillContainer.Origin = state ? Anchor.Centre : Anchor.TopLeft; });
|
||||||
AddToggleStep("Autosize Container", state =>
|
AddToggleStep("Autosize Container", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
fillContainer.RelativeSizeAxes = Axes.None;
|
fillContainer.RelativeSizeAxes = Axes.None;
|
||||||
fillContainer.AutoSizeAxes = Axes.Both;
|
fillContainer.AutoSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fillContainer.AutoSizeAxes = Axes.None;
|
fillContainer.AutoSizeAxes = Axes.None;
|
||||||
fillContainer.RelativeSizeAxes = Axes.Both;
|
fillContainer.RelativeSizeAxes = Axes.Both;
|
||||||
fillContainer.Width = 1;
|
fillContainer.Width = 1;
|
||||||
fillContainer.Height = 1;
|
fillContainer.Height = 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AddToggleStep("Rotate children", state =>
|
AddToggleStep("Rotate children", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.RotateTo(45f, 1000);
|
child.RotateTo(45f, 1000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.RotateTo(0f, 1000);
|
child.RotateTo(0f, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AddToggleStep("Shear children", state =>
|
AddToggleStep("Shear children", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.Shear = new Vector2(0.2f, 0.2f);
|
child.Shear = new Vector2(0.2f, 0.2f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.Shear = Vector2.Zero;
|
child.Shear = Vector2.Zero;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AddToggleStep("Scale children", state =>
|
AddToggleStep("Scale children", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.ScaleTo(1.25f, 1000);
|
child.ScaleTo(1.25f, 1000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.ScaleTo(1f, 1000);
|
child.ScaleTo(1f, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AddToggleStep("Randomly scale children", state =>
|
AddToggleStep("Randomly scale children", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.ScaleTo(RNG.NextSingle(1, 2), 1000);
|
child.ScaleTo(RNG.NextSingle(1, 2), 1000);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.ScaleTo(1f, 1000);
|
child.ScaleTo(1f, 1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AddToggleStep("Randomly set child origins", state =>
|
AddToggleStep("Randomly set child origins", state =>
|
||||||
{
|
{
|
||||||
if (state)
|
if (state)
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
{
|
{
|
||||||
switch (RNG.Next(9))
|
switch (RNG.Next(9))
|
||||||
{
|
{
|
||||||
case 0: child.Origin = Anchor.TopLeft; break;
|
case 0: child.Origin = Anchor.TopLeft; break;
|
||||||
case 1: child.Origin = Anchor.TopCentre; break;
|
case 1: child.Origin = Anchor.TopCentre; break;
|
||||||
case 2: child.Origin = Anchor.TopRight; break;
|
case 2: child.Origin = Anchor.TopRight; break;
|
||||||
case 3: child.Origin = Anchor.CentreLeft; break;
|
case 3: child.Origin = Anchor.CentreLeft; break;
|
||||||
case 4: child.Origin = Anchor.Centre; break;
|
case 4: child.Origin = Anchor.Centre; break;
|
||||||
case 5: child.Origin = Anchor.CentreRight; break;
|
case 5: child.Origin = Anchor.CentreRight; break;
|
||||||
case 6: child.Origin = Anchor.BottomLeft; break;
|
case 6: child.Origin = Anchor.BottomLeft; break;
|
||||||
case 7: child.Origin = Anchor.BottomCentre; break;
|
case 7: child.Origin = Anchor.BottomCentre; break;
|
||||||
case 8: child.Origin = Anchor.BottomRight; break;
|
case 8: child.Origin = Anchor.BottomRight; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var child in fillContainer.Children)
|
foreach (var child in fillContainer.Children)
|
||||||
child.Origin = originDropdown.Current;
|
child.Origin = originDropdown.Current;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddToggleStep("Stop adding children", state => { doNotAddChildren = state; });
|
AddToggleStep("Stop adding children", state => { doNotAddChildren = state; });
|
||||||
|
|
||||||
scheduledAdder?.Cancel();
|
scheduledAdder?.Cancel();
|
||||||
scheduledAdder = Scheduler.AddDelayed(
|
scheduledAdder = Scheduler.AddDelayed(
|
||||||
() =>
|
() =>
|
||||||
{
|
{
|
||||||
if (fillContainer.Parent == null)
|
if (fillContainer.Parent == null)
|
||||||
scheduledAdder.Cancel();
|
scheduledAdder.Cancel();
|
||||||
|
|
||||||
if (doNotAddChildren)
|
if (doNotAddChildren)
|
||||||
{
|
{
|
||||||
fillContainer.Invalidate();
|
fillContainer.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fillContainer.Children.Count < 1000 && !doNotAddChildren)
|
if (fillContainer.Children.Count < 1000 && !doNotAddChildren)
|
||||||
{
|
{
|
||||||
fillContainer.Add(new Container
|
fillContainer.Add(new Container
|
||||||
{
|
{
|
||||||
Anchor = childAnchor,
|
Anchor = childAnchor,
|
||||||
Origin = childOrigin,
|
Origin = childOrigin,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Width = 50,
|
Width = 50,
|
||||||
Height = 50,
|
Height = 50,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
Position = new Vector2(0.5f, 0.5f),
|
Position = new Vector2(0.5f, 0.5f),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Text = fillContainer.Children.Count.ToString()
|
Text = fillContainer.Children.Count.ToString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
100,
|
100,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[FlowTestCase(FlowTestCase.Full)]
|
[FlowTestCase(FlowTestCase.Full)]
|
||||||
private void test1()
|
private void test1()
|
||||||
{
|
{
|
||||||
fillContainer.Direction = FillDirection.Full;
|
fillContainer.Direction = FillDirection.Full;
|
||||||
fillContainer.Spacing = new Vector2(5, 5);
|
fillContainer.Spacing = new Vector2(5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
[FlowTestCase(FlowTestCase.Horizontal)]
|
[FlowTestCase(FlowTestCase.Horizontal)]
|
||||||
private void test2()
|
private void test2()
|
||||||
{
|
{
|
||||||
fillContainer.Direction = FillDirection.Horizontal;
|
fillContainer.Direction = FillDirection.Horizontal;
|
||||||
fillContainer.Spacing = new Vector2(5, 5);
|
fillContainer.Spacing = new Vector2(5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
[FlowTestCase(FlowTestCase.Vertical)]
|
[FlowTestCase(FlowTestCase.Vertical)]
|
||||||
private void test3()
|
private void test3()
|
||||||
{
|
{
|
||||||
fillContainer.Direction = FillDirection.Vertical;
|
fillContainer.Direction = FillDirection.Vertical;
|
||||||
fillContainer.Spacing = new Vector2(5, 5);
|
fillContainer.Spacing = new Vector2(5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestCaseDropdownHeader : DropdownHeader
|
private class TestCaseDropdownHeader : DropdownHeader
|
||||||
{
|
{
|
||||||
private readonly SpriteText label;
|
private readonly SpriteText label;
|
||||||
|
|
||||||
protected internal override string Label
|
protected internal override string Label
|
||||||
{
|
{
|
||||||
get { return label.Text; }
|
get { return label.Text; }
|
||||||
set { label.Text = value; }
|
set { label.Text = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseDropdownHeader()
|
public TestCaseDropdownHeader()
|
||||||
{
|
{
|
||||||
Foreground.Padding = new MarginPadding(4);
|
Foreground.Padding = new MarginPadding(4);
|
||||||
BackgroundColour = new Color4(100, 100, 100, 255);
|
BackgroundColour = new Color4(100, 100, 100, 255);
|
||||||
BackgroundColourHover = Color4.HotPink;
|
BackgroundColourHover = Color4.HotPink;
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
label = new SpriteText(),
|
label = new SpriteText(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnchorDropdown : BasicDropdown<Anchor>
|
private class AnchorDropdown : BasicDropdown<Anchor>
|
||||||
{
|
{
|
||||||
protected override DropdownHeader CreateHeader() => new TestCaseDropdownHeader();
|
protected override DropdownHeader CreateHeader() => new TestCaseDropdownHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnchorDropdownMenuItem : DropdownMenuItem<Anchor>
|
private class AnchorDropdownMenuItem : DropdownMenuItem<Anchor>
|
||||||
{
|
{
|
||||||
public AnchorDropdownMenuItem(Anchor anchor)
|
public AnchorDropdownMenuItem(Anchor anchor)
|
||||||
: base(anchor.ToString(), anchor)
|
: base(anchor.ToString(), anchor)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FillDirectionDropdown : BasicDropdown<FlowTestCase>
|
private class FillDirectionDropdown : BasicDropdown<FlowTestCase>
|
||||||
{
|
{
|
||||||
protected override DropdownHeader CreateHeader() => new TestCaseDropdownHeader();
|
protected override DropdownHeader CreateHeader() => new TestCaseDropdownHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FillDirectionDropdownMenuItem : DropdownMenuItem<FlowTestCase>
|
private class FillDirectionDropdownMenuItem : DropdownMenuItem<FlowTestCase>
|
||||||
{
|
{
|
||||||
public FillDirectionDropdownMenuItem(FlowTestCase testCase)
|
public FillDirectionDropdownMenuItem(FlowTestCase testCase)
|
||||||
: base(testCase.ToString(), testCase)
|
: base(testCase.ToString(), testCase)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
private class FlowTestCaseAttribute : Attribute
|
private class FlowTestCaseAttribute : Attribute
|
||||||
{
|
{
|
||||||
public FlowTestCase TestCase { get; }
|
public FlowTestCase TestCase { get; }
|
||||||
|
|
||||||
public FlowTestCaseAttribute(FlowTestCase testCase)
|
public FlowTestCaseAttribute(FlowTestCase testCase)
|
||||||
{
|
{
|
||||||
TestCase = testCase;
|
TestCase = testCase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum FlowTestCase
|
private enum FlowTestCase
|
||||||
{
|
{
|
||||||
Full,
|
Full,
|
||||||
Horizontal,
|
Horizontal,
|
||||||
Vertical,
|
Vertical,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,207 +1,207 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("sprite stretching")]
|
[System.ComponentModel.Description("sprite stretching")]
|
||||||
public class TestCaseFillModes : GridTestCase
|
public class TestCaseFillModes : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseFillModes() : base(3, 3)
|
public TestCaseFillModes() : base(3, 3)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
FillMode[] fillModes =
|
FillMode[] fillModes =
|
||||||
{
|
{
|
||||||
FillMode.Stretch,
|
FillMode.Stretch,
|
||||||
FillMode.Fit,
|
FillMode.Fit,
|
||||||
FillMode.Fill,
|
FillMode.Fill,
|
||||||
};
|
};
|
||||||
|
|
||||||
float[] aspects = { 1, 2, 0.5f };
|
float[] aspects = { 1, 2, 0.5f };
|
||||||
|
|
||||||
for (int i = 0; i < Rows; ++i)
|
for (int i = 0; i < Rows; ++i)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < Cols; ++j)
|
for (int j = 0; j < Cols; ++j)
|
||||||
{
|
{
|
||||||
Cell(i, j).AddRange(new Drawable[]
|
Cell(i, j).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = $"{nameof(FillMode)}=FillMode.{fillModes[i]}, {nameof(FillAspectRatio)}={aspects[j]}",
|
Text = $"{nameof(FillMode)}=FillMode.{fillModes[i]}, {nameof(FillAspectRatio)}={aspects[j]}",
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
},
|
},
|
||||||
new Sprite
|
new Sprite
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = texture,
|
Texture = texture,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
FillMode = fillModes[i],
|
FillMode = fillModes[i],
|
||||||
FillAspectRatio = aspects[j],
|
FillAspectRatio = aspects[j],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Texture texture;
|
private Texture texture;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore store)
|
private void load(TextureStore store)
|
||||||
{
|
{
|
||||||
texture = store.Get(@"sample-texture");
|
texture = store.Get(@"sample-texture");
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PaddedBox : Container
|
private class PaddedBox : Container
|
||||||
{
|
{
|
||||||
private readonly SpriteText t1;
|
private readonly SpriteText t1;
|
||||||
private readonly SpriteText t2;
|
private readonly SpriteText t2;
|
||||||
private readonly SpriteText t3;
|
private readonly SpriteText t3;
|
||||||
private readonly SpriteText t4;
|
private readonly SpriteText t4;
|
||||||
|
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
public PaddedBox(Color4 colour)
|
public PaddedBox(Color4 colour)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colour,
|
Colour = colour,
|
||||||
},
|
},
|
||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
t1 = new SpriteText
|
t1 = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
t2 = new SpriteText
|
t2 = new SpriteText
|
||||||
{
|
{
|
||||||
Rotation = 90,
|
Rotation = 90,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
t3 = new SpriteText
|
t3 = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.BottomCentre
|
Origin = Anchor.BottomCentre
|
||||||
},
|
},
|
||||||
t4 = new SpriteText
|
t4 = new SpriteText
|
||||||
{
|
{
|
||||||
Rotation = -90,
|
Rotation = -90,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||||
{
|
{
|
||||||
t1.Text = (Padding.Top > 0 ? $"p{Padding.Top}" : string.Empty) + (Margin.Top > 0 ? $"m{Margin.Top}" : string.Empty);
|
t1.Text = (Padding.Top > 0 ? $"p{Padding.Top}" : string.Empty) + (Margin.Top > 0 ? $"m{Margin.Top}" : string.Empty);
|
||||||
t2.Text = (Padding.Right > 0 ? $"p{Padding.Right}" : string.Empty) + (Margin.Right > 0 ? $"m{Margin.Right}" : string.Empty);
|
t2.Text = (Padding.Right > 0 ? $"p{Padding.Right}" : string.Empty) + (Margin.Right > 0 ? $"m{Margin.Right}" : string.Empty);
|
||||||
t3.Text = (Padding.Bottom > 0 ? $"p{Padding.Bottom}" : string.Empty) + (Margin.Bottom > 0 ? $"m{Margin.Bottom}" : string.Empty);
|
t3.Text = (Padding.Bottom > 0 ? $"p{Padding.Bottom}" : string.Empty) + (Margin.Bottom > 0 ? $"m{Margin.Bottom}" : string.Empty);
|
||||||
t4.Text = (Padding.Left > 0 ? $"p{Padding.Left}" : string.Empty) + (Margin.Left > 0 ? $"m{Margin.Left}" : string.Empty);
|
t4.Text = (Padding.Left > 0 ? $"p{Padding.Left}" : string.Empty) + (Margin.Left > 0 ? $"m{Margin.Left}" : string.Empty);
|
||||||
|
|
||||||
return base.Invalidate(invalidation, source, shallPropagate);
|
return base.Invalidate(invalidation, source, shallPropagate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
Position += state.Mouse.Delta;
|
Position += state.Mouse.Delta;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragEnd(InputState state) => true;
|
protected override bool OnDragEnd(InputState state) => true;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state) => true;
|
protected override bool OnDragStart(InputState state) => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Test Cases
|
#region Test Cases
|
||||||
|
|
||||||
private const float container_width = 60;
|
private const float container_width = 60;
|
||||||
private Box fitBox;
|
private Box fitBox;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that using <see cref="FillMode.Fit"/> inside a <see cref="FlowContainer{T}"/> that is autosizing in one axis doesn't result in autosize feedback loops.
|
/// Tests that using <see cref="FillMode.Fit"/> inside a <see cref="FlowContainer{T}"/> that is autosizing in one axis doesn't result in autosize feedback loops.
|
||||||
/// Various sizes of the box are tested to ensure that non-one sizes also don't lead to erroneous sizes.
|
/// Various sizes of the box are tested to ensure that non-one sizes also don't lead to erroneous sizes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">The relative size of the box that is fitting.</param>
|
/// <param name="value">The relative size of the box that is fitting.</param>
|
||||||
[TestCase(0f)]
|
[TestCase(0f)]
|
||||||
[TestCase(0.5f)]
|
[TestCase(0.5f)]
|
||||||
[TestCase(1f)]
|
[TestCase(1f)]
|
||||||
public void TestFitInsideFlow(float value)
|
public void TestFitInsideFlow(float value)
|
||||||
{
|
{
|
||||||
ClearInternal();
|
ClearInternal();
|
||||||
AddInternal(new FillFlowContainer
|
AddInternal(new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Width = container_width,
|
Width = container_width,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
fitBox = new Box
|
fitBox = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fit
|
FillMode = FillMode.Fit
|
||||||
},
|
},
|
||||||
// A box which forces the minimum dimension of the autosize flow container to be the horizontal dimension
|
// A box which forces the minimum dimension of the autosize flow container to be the horizontal dimension
|
||||||
new Box { Size = new Vector2(container_width, container_width * 2) }
|
new Box { Size = new Vector2(container_width, container_width * 2) }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Set size", () => fitBox.Size = new Vector2(value));
|
AddStep("Set size", () => fitBox.Size = new Vector2(value));
|
||||||
|
|
||||||
var expectedSize = new Vector2(container_width * value, container_width * value);
|
var expectedSize = new Vector2(container_width * value, container_width * value);
|
||||||
|
|
||||||
AddAssert("Check size before invalidate (1/2)", () => fitBox.DrawSize == expectedSize);
|
AddAssert("Check size before invalidate (1/2)", () => fitBox.DrawSize == expectedSize);
|
||||||
AddAssert("Check size before invalidate (2/2)", () => fitBox.DrawSize == expectedSize);
|
AddAssert("Check size before invalidate (2/2)", () => fitBox.DrawSize == expectedSize);
|
||||||
AddStep("Invalidate", () => fitBox.Invalidate());
|
AddStep("Invalidate", () => fitBox.Invalidate());
|
||||||
AddAssert("Check size after invalidate (1/2)", () => fitBox.DrawSize == expectedSize);
|
AddAssert("Check size after invalidate (1/2)", () => fitBox.DrawSize == expectedSize);
|
||||||
AddAssert("Check size after invalidate (2/2)", () => fitBox.DrawSize == expectedSize);
|
AddAssert("Check size after invalidate (2/2)", () => fitBox.DrawSize == expectedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,370 +1,370 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseGridContainer : TestCase
|
public class TestCaseGridContainer : TestCase
|
||||||
{
|
{
|
||||||
private readonly GridContainer grid;
|
private readonly GridContainer grid;
|
||||||
|
|
||||||
public TestCaseGridContainer()
|
public TestCaseGridContainer()
|
||||||
{
|
{
|
||||||
Add(new Container
|
Add(new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
BorderColour = Color4.White,
|
BorderColour = Color4.White,
|
||||||
BorderThickness = 2,
|
BorderThickness = 2,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
AlwaysPresent = true
|
AlwaysPresent = true
|
||||||
},
|
},
|
||||||
grid = new GridContainer { RelativeSizeAxes = Axes.Both }
|
grid = new GridContainer { RelativeSizeAxes = Axes.Both }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Blank grid", reset);
|
AddStep("Blank grid", reset);
|
||||||
AddStep("1-cell (auto)", () =>
|
AddStep("1-cell (auto)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[] { new Drawable[] { new FillBox() } };
|
grid.Content = new[] { new Drawable[] { new FillBox() } };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("1-cell (absolute)", () =>
|
AddStep("1-cell (absolute)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[] { new Drawable[] { new FillBox() } };
|
grid.Content = new[] { new Drawable[] { new FillBox() } };
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 100) };
|
grid.RowDimensions = grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Absolute, 100) };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("1-cell (relative)", () =>
|
AddStep("1-cell (relative)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
grid.RowDimensions = grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("1-cell (mixed)", () =>
|
AddStep("1-cell (mixed)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
||||||
grid.RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 100) };
|
grid.RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, 100) };
|
||||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("1-cell (mixed) 2", () =>
|
AddStep("1-cell (mixed) 2", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox() } };
|
||||||
grid.RowDimensions = new [] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
grid.RowDimensions = new [] { new Dimension(GridSizeMode.Relative, 0.5f) };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell row (auto)", () =>
|
AddStep("3-cell row (auto)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell row (absolute)", () =>
|
AddStep("3-cell row (absolute)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Absolute, 100),
|
new Dimension(GridSizeMode.Absolute, 100),
|
||||||
new Dimension(GridSizeMode.Absolute, 150)
|
new Dimension(GridSizeMode.Absolute, 150)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell row (relative)", () =>
|
AddStep("3-cell row (relative)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Relative, 0.1f),
|
new Dimension(GridSizeMode.Relative, 0.1f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f),
|
new Dimension(GridSizeMode.Relative, 0.2f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.3f)
|
new Dimension(GridSizeMode.Relative, 0.3f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell row (mixed)", () =>
|
AddStep("3-cell row (mixed)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
grid.Content = new [] { new Drawable[] { new FillBox(), new FillBox(), new FillBox() } };
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f)
|
new Dimension(GridSizeMode.Relative, 0.2f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell column (auto)", () =>
|
AddStep("3-cell column (auto)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() }
|
new Drawable[] { new FillBox() }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell column (absolute)", () =>
|
AddStep("3-cell column (absolute)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() }
|
new Drawable[] { new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Absolute, 100),
|
new Dimension(GridSizeMode.Absolute, 100),
|
||||||
new Dimension(GridSizeMode.Absolute, 150)
|
new Dimension(GridSizeMode.Absolute, 150)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell column (relative)", () =>
|
AddStep("3-cell column (relative)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() }
|
new Drawable[] { new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Relative, 0.1f),
|
new Dimension(GridSizeMode.Relative, 0.1f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f),
|
new Dimension(GridSizeMode.Relative, 0.2f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.3f)
|
new Dimension(GridSizeMode.Relative, 0.3f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3-cell column (mixed)", () =>
|
AddStep("3-cell column (mixed)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() },
|
new Drawable[] { new FillBox() },
|
||||||
new Drawable[] { new FillBox() }
|
new Drawable[] { new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f)
|
new Dimension(GridSizeMode.Relative, 0.2f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3x3-cell (auto)", () =>
|
AddStep("3x3-cell (auto)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3x3-cell (absolute)", () =>
|
AddStep("3x3-cell (absolute)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Absolute, 100),
|
new Dimension(GridSizeMode.Absolute, 100),
|
||||||
new Dimension(GridSizeMode.Absolute, 150)
|
new Dimension(GridSizeMode.Absolute, 150)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3x3-cell (relative)", () =>
|
AddStep("3x3-cell (relative)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Relative, 0.1f),
|
new Dimension(GridSizeMode.Relative, 0.1f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f),
|
new Dimension(GridSizeMode.Relative, 0.2f),
|
||||||
new Dimension(GridSizeMode.Relative, 0.3f)
|
new Dimension(GridSizeMode.Relative, 0.3f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("3x3-cell (mixed)", () =>
|
AddStep("3x3-cell (mixed)", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new[]
|
grid.RowDimensions = grid.ColumnDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 50),
|
new Dimension(GridSizeMode.Absolute, 50),
|
||||||
new Dimension(GridSizeMode.Relative, 0.2f)
|
new Dimension(GridSizeMode.Relative, 0.2f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Larger sides", () =>
|
AddStep("Larger sides", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.ColumnDimensions = grid.RowDimensions = new[]
|
grid.ColumnDimensions = grid.RowDimensions = new[]
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Relative, 0.4f),
|
new Dimension(GridSizeMode.Relative, 0.4f),
|
||||||
new Dimension(),
|
new Dimension(),
|
||||||
new Dimension(GridSizeMode.Relative, 0.4f)
|
new Dimension(GridSizeMode.Relative, 0.4f)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Separated", () =>
|
AddStep("Separated", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), null, new FillBox() },
|
new Drawable[] { new FillBox(), null, new FillBox() },
|
||||||
null,
|
null,
|
||||||
new Drawable[] { new FillBox(), null, new FillBox() }
|
new Drawable[] { new FillBox(), null, new FillBox() }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Separated 2", () =>
|
AddStep("Separated 2", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), null, new FillBox(), null },
|
new Drawable[] { new FillBox(), null, new FillBox(), null },
|
||||||
null,
|
null,
|
||||||
new Drawable[] { new FillBox(), null, new FillBox(), null },
|
new Drawable[] { new FillBox(), null, new FillBox(), null },
|
||||||
null
|
null
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Nested grids", () =>
|
AddStep("Nested grids", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new FillBox(),
|
new FillBox(),
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox() },
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new FillBox(),
|
new FillBox(),
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillBox()
|
new FillBox()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Auto size", () =>
|
AddStep("Auto size", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[] { new Box { Size = new Vector2(30) }, new FillBox(), new FillBox() },
|
new Drawable[] { new Box { Size = new Vector2(30) }, new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() },
|
||||||
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
new Drawable[] { new FillBox(), new FillBox(), new FillBox() }
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Relative, 0.5f) };
|
grid.RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Relative, 0.5f) };
|
||||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Relative, 0.5f) };
|
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.Relative, 0.5f) };
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Autosizing child", () =>
|
AddStep("Autosizing child", () =>
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
grid.Content = new[]
|
grid.Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new Box { Size = new Vector2(100, 50) }
|
Child = new Box { Size = new Vector2(100, 50) }
|
||||||
},
|
},
|
||||||
new FillBox()
|
new FillBox()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) };
|
grid.ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset()
|
private void reset()
|
||||||
{
|
{
|
||||||
grid.ClearInternal();
|
grid.ClearInternal();
|
||||||
grid.RowDimensions = grid.ColumnDimensions = new Dimension[] { };
|
grid.RowDimensions = grid.ColumnDimensions = new Dimension[] { };
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FillBox : Box
|
private class FillBox : Box
|
||||||
{
|
{
|
||||||
public FillBox()
|
public FillBox()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Colour = new Color4(RNG.NextSingle(1), RNG.NextSingle(1), RNG.NextSingle(1), 1);
|
Colour = new Color4(RNG.NextSingle(1), RNG.NextSingle(1), RNG.NextSingle(1), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseHollowEdgeEffect : GridTestCase
|
public class TestCaseHollowEdgeEffect : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseHollowEdgeEffect() : base(2, 2)
|
public TestCaseHollowEdgeEffect() : base(2, 2)
|
||||||
{
|
{
|
||||||
const float size = 60;
|
const float size = 60;
|
||||||
|
|
||||||
float[] cornerRadii = { 0, 0.5f, 0, 0.5f };
|
float[] cornerRadii = { 0, 0.5f, 0, 0.5f };
|
||||||
float[] alphas = { 0.5f, 0.5f, 0, 0 };
|
float[] alphas = { 0.5f, 0.5f, 0, 0 };
|
||||||
EdgeEffectParameters[] edgeEffects =
|
EdgeEffectParameters[] edgeEffects =
|
||||||
{
|
{
|
||||||
new EdgeEffectParameters
|
new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Color4.Khaki,
|
Colour = Color4.Khaki,
|
||||||
Radius = size,
|
Radius = size,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
},
|
},
|
||||||
new EdgeEffectParameters
|
new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Color4.Khaki,
|
Colour = Color4.Khaki,
|
||||||
Radius = size,
|
Radius = size,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
},
|
},
|
||||||
new EdgeEffectParameters
|
new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Color4.Khaki,
|
Colour = Color4.Khaki,
|
||||||
Radius = size,
|
Radius = size,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
},
|
},
|
||||||
new EdgeEffectParameters
|
new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Colour = Color4.Khaki,
|
Colour = Color4.Khaki,
|
||||||
Radius = size,
|
Radius = size,
|
||||||
Hollow = true,
|
Hollow = true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < Rows * Cols; ++i)
|
for (int i = 0; i < Rows * Cols; ++i)
|
||||||
{
|
{
|
||||||
Cell(i).AddRange(new Drawable[]
|
Cell(i).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = $"{nameof(CornerRadius)}={cornerRadii[i]} {nameof(Alpha)}={alphas[i]}",
|
Text = $"{nameof(CornerRadius)}={cornerRadii[i]} {nameof(Alpha)}={alphas[i]}",
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(size),
|
Size = new Vector2(size),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
EdgeEffect = edgeEffects[i],
|
EdgeEffect = edgeEffects[i],
|
||||||
CornerRadius = cornerRadii[i] * size,
|
CornerRadius = cornerRadii[i] * size,
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Aqua,
|
Colour = Color4.Aqua,
|
||||||
Alpha = alphas[i],
|
Alpha = alphas[i],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,208 +1,208 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
using osu.Framework.Graphics.OpenGL.Textures;
|
using osu.Framework.Graphics.OpenGL.Textures;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("live path optimiastion")]
|
[System.ComponentModel.Description("live path optimiastion")]
|
||||||
public class TestCaseInputResampler : GridTestCase
|
public class TestCaseInputResampler : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseInputResampler() : base(3, 3)
|
public TestCaseInputResampler() : base(3, 3)
|
||||||
{
|
{
|
||||||
const int width = 2;
|
const int width = 2;
|
||||||
Texture gradientTexture = new Texture(width, 1, true);
|
Texture gradientTexture = new Texture(width, 1, true);
|
||||||
byte[] data = new byte[width * 4];
|
byte[] data = new byte[width * 4];
|
||||||
for (int i = 0; i < width; ++i)
|
for (int i = 0; i < width; ++i)
|
||||||
{
|
{
|
||||||
float brightness = (float)i / (width - 1);
|
float brightness = (float)i / (width - 1);
|
||||||
int index = i * 4;
|
int index = i * 4;
|
||||||
data[index + 0] = (byte)(brightness * 255);
|
data[index + 0] = (byte)(brightness * 255);
|
||||||
data[index + 1] = (byte)(brightness * 255);
|
data[index + 1] = (byte)(brightness * 255);
|
||||||
data[index + 2] = (byte)(brightness * 255);
|
data[index + 2] = (byte)(brightness * 255);
|
||||||
data[index + 3] = 255;
|
data[index + 3] = 255;
|
||||||
}
|
}
|
||||||
gradientTexture.SetData(new TextureUpload(data));
|
gradientTexture.SetData(new TextureUpload(data));
|
||||||
|
|
||||||
SpriteText[] text = new SpriteText[6];
|
SpriteText[] text = new SpriteText[6];
|
||||||
|
|
||||||
Cell(0, 0).AddRange(new Drawable[]
|
Cell(0, 0).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[0] = createLabel("Raw"),
|
text[0] = createLabel("Raw"),
|
||||||
new ArcPath(true, true, new InputResampler(), gradientTexture, Color4.Green, text[0]),
|
new ArcPath(true, true, new InputResampler(), gradientTexture, Color4.Green, text[0]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(0, 1).AddRange(new Drawable[]
|
Cell(0, 1).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[1] = createLabel("Rounded (resembles mouse input)"),
|
text[1] = createLabel("Rounded (resembles mouse input)"),
|
||||||
new ArcPath(true, false, new InputResampler(), gradientTexture, Color4.Blue, text[1]),
|
new ArcPath(true, false, new InputResampler(), gradientTexture, Color4.Blue, text[1]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(0, 2).AddRange(new Drawable[]
|
Cell(0, 2).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[2] = createLabel("Custom: Smoothed=0, Raw=0"),
|
text[2] = createLabel("Custom: Smoothed=0, Raw=0"),
|
||||||
new UserDrawnPath
|
new UserDrawnPath
|
||||||
{
|
{
|
||||||
DrawText = text[2],
|
DrawText = text[2],
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(1, 0).AddRange(new Drawable[]
|
Cell(1, 0).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[3] = createLabel("Smoothed raw"),
|
text[3] = createLabel("Smoothed raw"),
|
||||||
new ArcPath(false, true, new InputResampler(), gradientTexture, Color4.Green, text[3]),
|
new ArcPath(false, true, new InputResampler(), gradientTexture, Color4.Green, text[3]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(1, 1).AddRange(new Drawable[]
|
Cell(1, 1).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[4] = createLabel("Smoothed rounded"),
|
text[4] = createLabel("Smoothed rounded"),
|
||||||
new ArcPath(false, false, new InputResampler(), gradientTexture, Color4.Blue, text[4]),
|
new ArcPath(false, false, new InputResampler(), gradientTexture, Color4.Blue, text[4]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(1, 2).AddRange(new Drawable[]
|
Cell(1, 2).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[5] = createLabel("Smoothed custom: Smoothed=0, Raw=0"),
|
text[5] = createLabel("Smoothed custom: Smoothed=0, Raw=0"),
|
||||||
new SmoothedUserDrawnPath
|
new SmoothedUserDrawnPath
|
||||||
{
|
{
|
||||||
DrawText = text[5],
|
DrawText = text[5],
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
InputResampler = new InputResampler(),
|
InputResampler = new InputResampler(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(2, 0).AddRange(new Drawable[]
|
Cell(2, 0).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[3] = createLabel("Force-smoothed raw"),
|
text[3] = createLabel("Force-smoothed raw"),
|
||||||
new ArcPath(false, true, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Green, text[3]),
|
new ArcPath(false, true, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Green, text[3]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(2, 1).AddRange(new Drawable[]
|
Cell(2, 1).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[4] = createLabel("Force-smoothed rounded"),
|
text[4] = createLabel("Force-smoothed rounded"),
|
||||||
new ArcPath(false, false, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Blue, text[4]),
|
new ArcPath(false, false, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Blue, text[4]),
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(2, 2).AddRange(new Drawable[]
|
Cell(2, 2).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
text[5] = createLabel("Force-smoothed custom: Smoothed=0, Raw=0"),
|
text[5] = createLabel("Force-smoothed custom: Smoothed=0, Raw=0"),
|
||||||
new SmoothedUserDrawnPath
|
new SmoothedUserDrawnPath
|
||||||
{
|
{
|
||||||
DrawText = text[5],
|
DrawText = text[5],
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Texture = gradientTexture,
|
Texture = gradientTexture,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
InputResampler = new InputResampler
|
InputResampler = new InputResampler
|
||||||
{
|
{
|
||||||
ResampleRawInput = true
|
ResampleRawInput = true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpriteText createLabel(string text) => new SpriteText
|
private SpriteText createLabel(string text) => new SpriteText
|
||||||
{
|
{
|
||||||
Text = text,
|
Text = text,
|
||||||
TextSize = 14,
|
TextSize = 14,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
};
|
};
|
||||||
|
|
||||||
private class SmoothedPath : Path
|
private class SmoothedPath : Path
|
||||||
{
|
{
|
||||||
protected SmoothedPath()
|
protected SmoothedPath()
|
||||||
{
|
{
|
||||||
PathWidth = 2;
|
PathWidth = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputResampler InputResampler { get; set; } = new InputResampler();
|
public InputResampler InputResampler { get; set; } = new InputResampler();
|
||||||
|
|
||||||
protected int NumVertices { get; set; }
|
protected int NumVertices { get; set; }
|
||||||
|
|
||||||
protected int NumRaw { get; set; }
|
protected int NumRaw { get; set; }
|
||||||
|
|
||||||
protected void AddRawVertex(Vector2 pos)
|
protected void AddRawVertex(Vector2 pos)
|
||||||
{
|
{
|
||||||
NumRaw++;
|
NumRaw++;
|
||||||
AddVertex(pos);
|
AddVertex(pos);
|
||||||
NumVertices++;
|
NumVertices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool AddSmoothedVertex(Vector2 pos)
|
protected bool AddSmoothedVertex(Vector2 pos)
|
||||||
{
|
{
|
||||||
NumRaw++;
|
NumRaw++;
|
||||||
bool foundOne = false;
|
bool foundOne = false;
|
||||||
foreach (Vector2 relevant in InputResampler.AddPosition(pos))
|
foreach (Vector2 relevant in InputResampler.AddPosition(pos))
|
||||||
{
|
{
|
||||||
AddVertex(relevant);
|
AddVertex(relevant);
|
||||||
NumVertices++;
|
NumVertices++;
|
||||||
foundOne = true;
|
foundOne = true;
|
||||||
}
|
}
|
||||||
return foundOne;
|
return foundOne;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ArcPath : SmoothedPath
|
private class ArcPath : SmoothedPath
|
||||||
{
|
{
|
||||||
public ArcPath(bool raw, bool keepFraction, InputResampler inputResampler, Texture texture, Color4 colour, SpriteText output)
|
public ArcPath(bool raw, bool keepFraction, InputResampler inputResampler, Texture texture, Color4 colour, SpriteText output)
|
||||||
{
|
{
|
||||||
InputResampler = inputResampler;
|
InputResampler = inputResampler;
|
||||||
const int target_raw = 1024;
|
const int target_raw = 1024;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Colour = colour;
|
Colour = colour;
|
||||||
|
|
||||||
for (int i = 0; i < target_raw; i++)
|
for (int i = 0; i < target_raw; i++)
|
||||||
{
|
{
|
||||||
float x = (float)(Math.Sin(i / (double)target_raw * (Math.PI * 0.5)) * 200) + 50.5f;
|
float x = (float)(Math.Sin(i / (double)target_raw * (Math.PI * 0.5)) * 200) + 50.5f;
|
||||||
float y = (float)(Math.Cos(i / (double)target_raw * (Math.PI * 0.5)) * 200) + 50.5f;
|
float y = (float)(Math.Cos(i / (double)target_raw * (Math.PI * 0.5)) * 200) + 50.5f;
|
||||||
Vector2 v = keepFraction ? new Vector2(x, y) : new Vector2((int)x, (int)y);
|
Vector2 v = keepFraction ? new Vector2(x, y) : new Vector2((int)x, (int)y);
|
||||||
if (raw)
|
if (raw)
|
||||||
AddRawVertex(v);
|
AddRawVertex(v);
|
||||||
else
|
else
|
||||||
AddSmoothedVertex(v);
|
AddSmoothedVertex(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.Text += ": Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
output.Text += ": Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UserDrawnPath : SmoothedPath
|
private class UserDrawnPath : SmoothedPath
|
||||||
{
|
{
|
||||||
public SpriteText DrawText;
|
public SpriteText DrawText;
|
||||||
|
|
||||||
protected virtual void AddUserVertex(Vector2 v) => AddRawVertex(v);
|
protected virtual void AddUserVertex(Vector2 v) => AddRawVertex(v);
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state)
|
protected override bool OnDragStart(InputState state)
|
||||||
{
|
{
|
||||||
AddUserVertex(state.Mouse.Position);
|
AddUserVertex(state.Mouse.Position);
|
||||||
DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
AddUserVertex(state.Mouse.Position);
|
AddUserVertex(state.Mouse.Position);
|
||||||
DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
|
||||||
return base.OnDrag(state);
|
return base.OnDrag(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SmoothedUserDrawnPath : UserDrawnPath
|
private class SmoothedUserDrawnPath : UserDrawnPath
|
||||||
{
|
{
|
||||||
protected override void AddUserVertex(Vector2 v) => AddSmoothedVertex(v);
|
protected override void AddUserVertex(Vector2 v) => AddSmoothedVertex(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,341 +1,341 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseIsMaskedAway : TestCase
|
public class TestCaseIsMaskedAway : TestCase
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box which is within the bounds of a parent is never masked away, regardless of whether the parent is masking or not.
|
/// Tests that a box which is within the bounds of a parent is never masked away, regardless of whether the parent is masking or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masking">Whether the box's parent is masking.</param>
|
/// <param name="masking">Whether the box's parent is masking.</param>
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
public void TestBoxInBounds(bool masking)
|
public void TestBoxInBounds(bool masking)
|
||||||
{
|
{
|
||||||
Box box;
|
Box box;
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = masking,
|
Masking = masking,
|
||||||
Child = box = new Box()
|
Child = box = new Box()
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box which is outside the bounds of a parent is never masked away if the parent is not masking.
|
/// Tests that a box which is outside the bounds of a parent is never masked away if the parent is not masking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBoxOutOfBoundsNoMasking()
|
public void TestBoxOutOfBoundsNoMasking()
|
||||||
{
|
{
|
||||||
Box box;
|
Box box;
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Child = box = new Box { Position = new Vector2(-1) }
|
Child = box = new Box { Position = new Vector2(-1) }
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box which is slightly outside the bounds of a masking parent is never masked away, regardless of its anchor/origin.
|
/// Tests that a box which is slightly outside the bounds of a masking parent is never masked away, regardless of its anchor/origin.
|
||||||
/// Ensures that all screen-space calculations are current by the time <see cref="Drawable.IsMaskedAway"/> is calculated.
|
/// Ensures that all screen-space calculations are current by the time <see cref="Drawable.IsMaskedAway"/> is calculated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="anchor">The box's anchor in the masking parent.</param>
|
/// <param name="anchor">The box's anchor in the masking parent.</param>
|
||||||
[TestCase(Anchor.TopLeft)]
|
[TestCase(Anchor.TopLeft)]
|
||||||
[TestCase(Anchor.TopRight)]
|
[TestCase(Anchor.TopRight)]
|
||||||
[TestCase(Anchor.BottomLeft)]
|
[TestCase(Anchor.BottomLeft)]
|
||||||
[TestCase(Anchor.BottomRight)]
|
[TestCase(Anchor.BottomRight)]
|
||||||
public void TestBoxSlightlyOutOfBoundsMasking(Anchor anchor)
|
public void TestBoxSlightlyOutOfBoundsMasking(Anchor anchor)
|
||||||
{
|
{
|
||||||
Box box;
|
Box box;
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Child = box = new Box
|
Child = box = new Box
|
||||||
{
|
{
|
||||||
Anchor = anchor,
|
Anchor = anchor,
|
||||||
Origin = anchor,
|
Origin = anchor,
|
||||||
Size = new Vector2(10),
|
Size = new Vector2(10),
|
||||||
Position = new Vector2((anchor & Anchor.x0) > 0 ? -5 : 5, (anchor & Anchor.y0) > 0 ? -5 : 5),
|
Position = new Vector2((anchor & Anchor.x0) > 0 ? -5 : 5, (anchor & Anchor.y0) > 0 ? -5 : 5),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box which is fully outside the bounds of a masking parent is always masked away, regardless of its anchor/origin.
|
/// Tests that a box which is fully outside the bounds of a masking parent is always masked away, regardless of its anchor/origin.
|
||||||
/// Ensures that all screen-space calculations are current by the time <see cref="Drawable.IsMaskedAway"/> is calculated.
|
/// Ensures that all screen-space calculations are current by the time <see cref="Drawable.IsMaskedAway"/> is calculated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="anchor">The box's anchor in the masking parent.</param>
|
/// <param name="anchor">The box's anchor in the masking parent.</param>
|
||||||
[TestCase(Anchor.TopLeft)]
|
[TestCase(Anchor.TopLeft)]
|
||||||
[TestCase(Anchor.TopRight)]
|
[TestCase(Anchor.TopRight)]
|
||||||
[TestCase(Anchor.BottomLeft)]
|
[TestCase(Anchor.BottomLeft)]
|
||||||
[TestCase(Anchor.BottomRight)]
|
[TestCase(Anchor.BottomRight)]
|
||||||
public void TestBoxFullyOutOfBoundsMasking(Anchor anchor)
|
public void TestBoxFullyOutOfBoundsMasking(Anchor anchor)
|
||||||
{
|
{
|
||||||
Box box;
|
Box box;
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Child = box = new Box
|
Child = box = new Box
|
||||||
{
|
{
|
||||||
Anchor = anchor,
|
Anchor = anchor,
|
||||||
Origin = anchor,
|
Origin = anchor,
|
||||||
Size = new Vector2(10),
|
Size = new Vector2(10),
|
||||||
Position = new Vector2((anchor & Anchor.x0) > 0 ? -20 : 20, (anchor & Anchor.y0) > 0 ? -20 : 20),
|
Position = new Vector2((anchor & Anchor.x0) > 0 ? -20 : 20, (anchor & Anchor.y0) > 0 ? -20 : 20),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box is never masked away when it and its proxy are within the bounds of their parents, regardless of whether their parents
|
/// Tests that a box is never masked away when it and its proxy are within the bounds of their parents, regardless of whether their parents
|
||||||
/// are masking or not.
|
/// are masking or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
||||||
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
||||||
[TestCase(false, false)]
|
[TestCase(false, false)]
|
||||||
[TestCase(true, true)]
|
[TestCase(true, true)]
|
||||||
public void TestBoxInBoundsWithProxyInBounds(bool boxMasking, bool proxyMasking)
|
public void TestBoxInBoundsWithProxyInBounds(bool boxMasking, bool proxyMasking)
|
||||||
{
|
{
|
||||||
var box = new Box();
|
var box = new Box();
|
||||||
|
|
||||||
ProxyDrawable proxy;
|
ProxyDrawable proxy;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = boxMasking,
|
Masking = boxMasking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = proxyMasking,
|
Masking = proxyMasking,
|
||||||
Child = proxy = box.CreateProxy()
|
Child = proxy = box.CreateProxy()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box is never masked away when its proxy is within the bounds of its parent, even if the box is outside the bounds of its parent.
|
/// Tests that a box is never masked away when its proxy is within the bounds of its parent, even if the box is outside the bounds of its parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masking">Whether the box's parent is masking. This does not affect the proxy's parent.</param>
|
/// <param name="masking">Whether the box's parent is masking. This does not affect the proxy's parent.</param>
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
public void TestBoxOutOfBoundsWithProxyInBounds(bool masking)
|
public void TestBoxOutOfBoundsWithProxyInBounds(bool masking)
|
||||||
{
|
{
|
||||||
var box = new Box { Position = new Vector2(-1) };
|
var box = new Box { Position = new Vector2(-1) };
|
||||||
|
|
||||||
ProxyDrawable proxy;
|
ProxyDrawable proxy;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = masking,
|
Masking = masking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
proxy = box.CreateProxy()
|
proxy = box.CreateProxy()
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that a box is only masked away when its proxy is masked away.
|
/// Tests that a box is only masked away when its proxy is masked away.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
||||||
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
||||||
/// <param name="shouldBeMaskedAway">Whether the box should be masked away.</param>
|
/// <param name="shouldBeMaskedAway">Whether the box should be masked away.</param>
|
||||||
[TestCase(false, false, false)]
|
[TestCase(false, false, false)]
|
||||||
[TestCase(false, true, true)]
|
[TestCase(false, true, true)]
|
||||||
[TestCase(true, false, false)]
|
[TestCase(true, false, false)]
|
||||||
[TestCase(true, true, true)]
|
[TestCase(true, true, true)]
|
||||||
public void TestBoxInBoundsWithProxyOutOfBounds(bool boxMasking, bool proxyMasking, bool shouldBeMaskedAway)
|
public void TestBoxInBoundsWithProxyOutOfBounds(bool boxMasking, bool proxyMasking, bool shouldBeMaskedAway)
|
||||||
{
|
{
|
||||||
var box = new Box();
|
var box = new Box();
|
||||||
|
|
||||||
ProxyDrawable proxy;
|
ProxyDrawable proxy;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = boxMasking,
|
Masking = boxMasking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Position = new Vector2(10),
|
Position = new Vector2(10),
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = proxyMasking,
|
Masking = proxyMasking,
|
||||||
Child = proxy = box.CreateProxy()
|
Child = proxy = box.CreateProxy()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
||||||
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that whether the box is out of bounds of its parent is not a consideration for masking, only whether its proxy is out of bounds of its parent.
|
/// Tests that whether the box is out of bounds of its parent is not a consideration for masking, only whether its proxy is out of bounds of its parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
||||||
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
/// <param name="proxyMasking">Whether the proxy's parent is masking.</param>
|
||||||
/// <param name="shouldBeMaskedAway">Whether the box should be masked away</param>
|
/// <param name="shouldBeMaskedAway">Whether the box should be masked away</param>
|
||||||
[TestCase(false, false, false)]
|
[TestCase(false, false, false)]
|
||||||
[TestCase(false, true, true)]
|
[TestCase(false, true, true)]
|
||||||
[TestCase(true, false, false)]
|
[TestCase(true, false, false)]
|
||||||
[TestCase(true, true, true)]
|
[TestCase(true, true, true)]
|
||||||
public void TestBoxOutOfBoundsWithProxyOutOfBounds(bool boxMasking, bool proxyMasking, bool shouldBeMaskedAway)
|
public void TestBoxOutOfBoundsWithProxyOutOfBounds(bool boxMasking, bool proxyMasking, bool shouldBeMaskedAway)
|
||||||
{
|
{
|
||||||
var box = new Box { Position = new Vector2(-1) };
|
var box = new Box { Position = new Vector2(-1) };
|
||||||
|
|
||||||
ProxyDrawable proxy;
|
ProxyDrawable proxy;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = boxMasking,
|
Masking = boxMasking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Position = new Vector2(10),
|
Position = new Vector2(10),
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = proxyMasking,
|
Masking = proxyMasking,
|
||||||
Child = proxy = box.CreateProxy()
|
Child = proxy = box.CreateProxy()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
||||||
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
AddAssert("Check proxy IsMaskedAway", () => !proxy.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that the box doesn't get masked away unless its most-proxied-proxy is masked away.
|
/// Tests that the box doesn't get masked away unless its most-proxied-proxy is masked away.
|
||||||
/// In this case, the most-proxied-proxy is never going to be masked away, because it is within the bounds of its parent.
|
/// In this case, the most-proxied-proxy is never going to be masked away, because it is within the bounds of its parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
||||||
/// <param name="proxy1Masking">Whether the parent of box's proxy is masking.</param>
|
/// <param name="proxy1Masking">Whether the parent of box's proxy is masking.</param>
|
||||||
/// <param name="proxy2Masking">Whether the parent of the proxy's proxy is masking.</param>
|
/// <param name="proxy2Masking">Whether the parent of the proxy's proxy is masking.</param>
|
||||||
[TestCase(false, false, false)]
|
[TestCase(false, false, false)]
|
||||||
[TestCase(true, false, false)]
|
[TestCase(true, false, false)]
|
||||||
[TestCase(true, true, false)]
|
[TestCase(true, true, false)]
|
||||||
[TestCase(true, true, true)]
|
[TestCase(true, true, true)]
|
||||||
[TestCase(false, true, true)]
|
[TestCase(false, true, true)]
|
||||||
public void TestBoxInBoundsWithProxy1OutOfBoundsWithProxy2InBounds(bool boxMasking, bool proxy1Masking, bool proxy2Masking)
|
public void TestBoxInBoundsWithProxy1OutOfBoundsWithProxy2InBounds(bool boxMasking, bool proxy1Masking, bool proxy2Masking)
|
||||||
{
|
{
|
||||||
var box = new Box();
|
var box = new Box();
|
||||||
var proxy1 = box.CreateProxy();
|
var proxy1 = box.CreateProxy();
|
||||||
var proxy2 = proxy1.CreateProxy();
|
var proxy2 = proxy1.CreateProxy();
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = boxMasking,
|
Masking = boxMasking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Position = new Vector2(10),
|
Position = new Vector2(10),
|
||||||
Masking = proxy1Masking,
|
Masking = proxy1Masking,
|
||||||
Child = proxy1
|
Child = proxy1
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = proxy2Masking,
|
Masking = proxy2Masking,
|
||||||
Child = proxy2
|
Child = proxy2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => !box.IsMaskedAway);
|
||||||
AddAssert("Check proxy1 IsMaskedAway", () => !proxy1.IsMaskedAway);
|
AddAssert("Check proxy1 IsMaskedAway", () => !proxy1.IsMaskedAway);
|
||||||
AddAssert("Check proxy2 IsMaskedAway", () => !proxy2.IsMaskedAway);
|
AddAssert("Check proxy2 IsMaskedAway", () => !proxy2.IsMaskedAway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests that whether the box is out of bounds of its parent is not a consideration for masking, only whether its most-proxied-proxy is out of bounds of its parent,
|
/// Tests that whether the box is out of bounds of its parent is not a consideration for masking, only whether its most-proxied-proxy is out of bounds of its parent,
|
||||||
/// and the most-proxied-proxy's parent is masking.
|
/// and the most-proxied-proxy's parent is masking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
/// <param name="boxMasking">Whether the box's parent is masking.</param>
|
||||||
/// <param name="proxy1Masking">Whether the parent of box's proxy is masking.</param>
|
/// <param name="proxy1Masking">Whether the parent of box's proxy is masking.</param>
|
||||||
/// <param name="proxy2Masking">Whether the parent of the proxy's proxy is masking.</param>
|
/// <param name="proxy2Masking">Whether the parent of the proxy's proxy is masking.</param>
|
||||||
/// <param name="shouldBeMaskedAway">Whether the box should be masked away.</param>
|
/// <param name="shouldBeMaskedAway">Whether the box should be masked away.</param>
|
||||||
[TestCase(false, false, false, false)]
|
[TestCase(false, false, false, false)]
|
||||||
[TestCase(true, false, false, false)]
|
[TestCase(true, false, false, false)]
|
||||||
[TestCase(true, true, false, false)]
|
[TestCase(true, true, false, false)]
|
||||||
[TestCase(true, true, true, true)]
|
[TestCase(true, true, true, true)]
|
||||||
[TestCase(false, true, true, true)]
|
[TestCase(false, true, true, true)]
|
||||||
[TestCase(false, false, true, true)]
|
[TestCase(false, false, true, true)]
|
||||||
public void TestBoxInBoundsWithProxy1OutOfBoundsWithProxy2OutOfBounds(bool boxMasking, bool proxy1Masking, bool proxy2Masking, bool shouldBeMaskedAway)
|
public void TestBoxInBoundsWithProxy1OutOfBoundsWithProxy2OutOfBounds(bool boxMasking, bool proxy1Masking, bool proxy2Masking, bool shouldBeMaskedAway)
|
||||||
{
|
{
|
||||||
var box = new Box();
|
var box = new Box();
|
||||||
var proxy1 = box.CreateProxy();
|
var proxy1 = box.CreateProxy();
|
||||||
var proxy2 = proxy1.CreateProxy();
|
var proxy2 = proxy1.CreateProxy();
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = boxMasking,
|
Masking = boxMasking,
|
||||||
Child = box
|
Child = box
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = proxy1Masking,
|
Masking = proxy1Masking,
|
||||||
Child = proxy1
|
Child = proxy1
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Position = new Vector2(10),
|
Position = new Vector2(10),
|
||||||
Masking = proxy2Masking,
|
Masking = proxy2Masking,
|
||||||
Child = proxy2
|
Child = proxy2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AddWaitStep(1, "Wait for UpdateSubTree");
|
AddWaitStep(1, "Wait for UpdateSubTree");
|
||||||
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
AddAssert("Check box IsMaskedAway", () => box.IsMaskedAway == shouldBeMaskedAway);
|
||||||
AddAssert("Check proxy1 IsMaskedAway", () => !proxy1.IsMaskedAway);
|
AddAssert("Check proxy1 IsMaskedAway", () => !proxy1.IsMaskedAway);
|
||||||
AddAssert("Check proxy2 IsMaskedAway", () => !proxy2.IsMaskedAway);
|
AddAssert("Check proxy2 IsMaskedAway", () => !proxy2.IsMaskedAway);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,165 +1,165 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseKeyBindings : GridTestCase
|
public class TestCaseKeyBindings : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseKeyBindings()
|
public TestCaseKeyBindings()
|
||||||
: base(2, 2)
|
: base(2, 2)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
Cell(0).Add(new KeyBindingTester(SimultaneousBindingMode.None));
|
Cell(0).Add(new KeyBindingTester(SimultaneousBindingMode.None));
|
||||||
Cell(1).Add(new KeyBindingTester(SimultaneousBindingMode.Unique));
|
Cell(1).Add(new KeyBindingTester(SimultaneousBindingMode.Unique));
|
||||||
Cell(2).Add(new KeyBindingTester(SimultaneousBindingMode.All));
|
Cell(2).Add(new KeyBindingTester(SimultaneousBindingMode.All));
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TestAction
|
private enum TestAction
|
||||||
{
|
{
|
||||||
A,
|
A,
|
||||||
S,
|
S,
|
||||||
D_or_F,
|
D_or_F,
|
||||||
Ctrl_A,
|
Ctrl_A,
|
||||||
Ctrl_S,
|
Ctrl_S,
|
||||||
Ctrl_D_or_F,
|
Ctrl_D_or_F,
|
||||||
Shift_A,
|
Shift_A,
|
||||||
Shift_S,
|
Shift_S,
|
||||||
Shift_D_or_F,
|
Shift_D_or_F,
|
||||||
Ctrl_Shift_A,
|
Ctrl_Shift_A,
|
||||||
Ctrl_Shift_S,
|
Ctrl_Shift_S,
|
||||||
Ctrl_Shift_D_or_F,
|
Ctrl_Shift_D_or_F,
|
||||||
Ctrl,
|
Ctrl,
|
||||||
Shift,
|
Shift,
|
||||||
Ctrl_And_Shift,
|
Ctrl_And_Shift,
|
||||||
Ctrl_Or_Shift,
|
Ctrl_Or_Shift,
|
||||||
LeftMouse,
|
LeftMouse,
|
||||||
RightMouse
|
RightMouse
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestInputManager : KeyBindingContainer<TestAction>
|
private class TestInputManager : KeyBindingContainer<TestAction>
|
||||||
{
|
{
|
||||||
public TestInputManager(SimultaneousBindingMode concurrencyMode = SimultaneousBindingMode.None) : base(concurrencyMode)
|
public TestInputManager(SimultaneousBindingMode concurrencyMode = SimultaneousBindingMode.None) : base(concurrencyMode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
|
||||||
{
|
{
|
||||||
new KeyBinding(InputKey.A, TestAction.A ),
|
new KeyBinding(InputKey.A, TestAction.A ),
|
||||||
new KeyBinding(InputKey.S, TestAction.S ),
|
new KeyBinding(InputKey.S, TestAction.S ),
|
||||||
new KeyBinding(InputKey.D, TestAction.D_or_F ),
|
new KeyBinding(InputKey.D, TestAction.D_or_F ),
|
||||||
new KeyBinding(InputKey.F, TestAction.D_or_F ),
|
new KeyBinding(InputKey.F, TestAction.D_or_F ),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.A }, TestAction.Ctrl_A ),
|
new KeyBinding(new[] { InputKey.Control, InputKey.A }, TestAction.Ctrl_A ),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.S }, TestAction.Ctrl_S ),
|
new KeyBinding(new[] { InputKey.Control, InputKey.S }, TestAction.Ctrl_S ),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.D }, TestAction.Ctrl_D_or_F ),
|
new KeyBinding(new[] { InputKey.Control, InputKey.D }, TestAction.Ctrl_D_or_F ),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.F }, TestAction.Ctrl_D_or_F ),
|
new KeyBinding(new[] { InputKey.Control, InputKey.F }, TestAction.Ctrl_D_or_F ),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Shift, InputKey.A }, TestAction.Shift_A ),
|
new KeyBinding(new[] { InputKey.Shift, InputKey.A }, TestAction.Shift_A ),
|
||||||
new KeyBinding(new[] { InputKey.Shift, InputKey.S }, TestAction.Shift_S ),
|
new KeyBinding(new[] { InputKey.Shift, InputKey.S }, TestAction.Shift_S ),
|
||||||
new KeyBinding(new[] { InputKey.Shift, InputKey.D }, TestAction.Shift_D_or_F ),
|
new KeyBinding(new[] { InputKey.Shift, InputKey.D }, TestAction.Shift_D_or_F ),
|
||||||
new KeyBinding(new[] { InputKey.Shift, InputKey.F }, TestAction.Shift_D_or_F ),
|
new KeyBinding(new[] { InputKey.Shift, InputKey.F }, TestAction.Shift_D_or_F ),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.A }, TestAction.Ctrl_Shift_A ),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.A }, TestAction.Ctrl_Shift_A ),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, TestAction.Ctrl_Shift_S),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.S }, TestAction.Ctrl_Shift_S),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.D }, TestAction.Ctrl_Shift_D_or_F),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.D }, TestAction.Ctrl_Shift_D_or_F),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, TestAction.Ctrl_Shift_D_or_F),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.F }, TestAction.Ctrl_Shift_D_or_F),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.Control }, TestAction.Ctrl),
|
new KeyBinding(new[] { InputKey.Control }, TestAction.Ctrl),
|
||||||
new KeyBinding(new[] { InputKey.Shift }, TestAction.Shift),
|
new KeyBinding(new[] { InputKey.Shift }, TestAction.Shift),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift }, TestAction.Ctrl_And_Shift),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift }, TestAction.Ctrl_And_Shift),
|
||||||
new KeyBinding(new[] { InputKey.Control }, TestAction.Ctrl_Or_Shift),
|
new KeyBinding(new[] { InputKey.Control }, TestAction.Ctrl_Or_Shift),
|
||||||
new KeyBinding(new[] { InputKey.Shift }, TestAction.Ctrl_Or_Shift),
|
new KeyBinding(new[] { InputKey.Shift }, TestAction.Ctrl_Or_Shift),
|
||||||
|
|
||||||
new KeyBinding(new[] { InputKey.MouseLeft }, TestAction.LeftMouse),
|
new KeyBinding(new[] { InputKey.MouseLeft }, TestAction.LeftMouse),
|
||||||
new KeyBinding(new[] { InputKey.MouseRight }, TestAction.RightMouse),
|
new KeyBinding(new[] { InputKey.MouseRight }, TestAction.RightMouse),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestButton : Button, IKeyBindingHandler<TestAction>
|
private class TestButton : Button, IKeyBindingHandler<TestAction>
|
||||||
{
|
{
|
||||||
private readonly TestAction action;
|
private readonly TestAction action;
|
||||||
|
|
||||||
public TestButton(TestAction action)
|
public TestButton(TestAction action)
|
||||||
{
|
{
|
||||||
this.action = action;
|
this.action = action;
|
||||||
|
|
||||||
BackgroundColour = Color4.SkyBlue;
|
BackgroundColour = Color4.SkyBlue;
|
||||||
Text = action.ToString().Replace('_', ' ');
|
Text = action.ToString().Replace('_', ' ');
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = 40;
|
Height = 40;
|
||||||
Width = 0.3f;
|
Width = 0.3f;
|
||||||
Padding = new MarginPadding(2);
|
Padding = new MarginPadding(2);
|
||||||
|
|
||||||
Background.Alpha = alphaTarget;
|
Background.Alpha = alphaTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float alphaTarget = 0.5f;
|
private float alphaTarget = 0.5f;
|
||||||
|
|
||||||
public bool OnPressed(TestAction action)
|
public bool OnPressed(TestAction action)
|
||||||
{
|
{
|
||||||
if (this.action == action)
|
if (this.action == action)
|
||||||
{
|
{
|
||||||
alphaTarget += 0.2f;
|
alphaTarget += 0.2f;
|
||||||
Background.FadeTo(alphaTarget, 100, Easing.OutQuint);
|
Background.FadeTo(alphaTarget, 100, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnReleased(TestAction action)
|
public bool OnReleased(TestAction action)
|
||||||
{
|
{
|
||||||
if (this.action == action)
|
if (this.action == action)
|
||||||
{
|
{
|
||||||
alphaTarget -= 0.2f;
|
alphaTarget -= 0.2f;
|
||||||
Background.FadeTo(alphaTarget, 100, Easing.OutQuint);
|
Background.FadeTo(alphaTarget, 100, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class KeyBindingTester : Container
|
private class KeyBindingTester : Container
|
||||||
{
|
{
|
||||||
public KeyBindingTester(SimultaneousBindingMode concurrency)
|
public KeyBindingTester(SimultaneousBindingMode concurrency)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = concurrency.ToString(),
|
Text = concurrency.ToString(),
|
||||||
},
|
},
|
||||||
new TestInputManager(concurrency)
|
new TestInputManager(concurrency)
|
||||||
{
|
{
|
||||||
Y = 30,
|
Y = 30,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ChildrenEnumerable = Enum.GetValues(typeof(TestAction)).Cast<TestAction>().Select(t => new TestButton(t))
|
ChildrenEnumerable = Enum.GetValues(typeof(TestAction)).Cast<TestAction>().Select(t => new TestButton(t))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +1,97 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("Rewinding of transforms that are important to layout.")]
|
[System.ComponentModel.Description("Rewinding of transforms that are important to layout.")]
|
||||||
public class TestCaseLayoutTransformRewinding : TestCase
|
public class TestCaseLayoutTransformRewinding : TestCase
|
||||||
{
|
{
|
||||||
private readonly ManualUpdateSubTreeContainer manualContainer;
|
private readonly ManualUpdateSubTreeContainer manualContainer;
|
||||||
|
|
||||||
public TestCaseLayoutTransformRewinding()
|
public TestCaseLayoutTransformRewinding()
|
||||||
{
|
{
|
||||||
Child = manualContainer = new ManualUpdateSubTreeContainer();
|
Child = manualContainer = new ManualUpdateSubTreeContainer();
|
||||||
|
|
||||||
testAutoSizeInstant();
|
testAutoSizeInstant();
|
||||||
testFlowInstant();
|
testFlowInstant();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testAutoSizeInstant()
|
private void testAutoSizeInstant()
|
||||||
{
|
{
|
||||||
AddStep("Initialize autosize test", () =>
|
AddStep("Initialize autosize test", () =>
|
||||||
{
|
{
|
||||||
manualContainer.Child = new Container
|
manualContainer.Child = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Child = new Box { Size = new Vector2(150) }
|
Child = new Box { Size = new Vector2(150) }
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Run to end", () => manualContainer.PerformUpdate(null));
|
AddStep("Run to end", () => manualContainer.PerformUpdate(null));
|
||||||
AddAssert("Size = 150", () => Precision.AlmostEquals(new Vector2(150), manualContainer.Child.Size));
|
AddAssert("Size = 150", () => Precision.AlmostEquals(new Vector2(150), manualContainer.Child.Size));
|
||||||
|
|
||||||
AddStep("Rewind", () => manualContainer.PerformUpdate(() => manualContainer.ApplyTransformsAt(-1, true)));
|
AddStep("Rewind", () => manualContainer.PerformUpdate(() => manualContainer.ApplyTransformsAt(-1, true)));
|
||||||
AddAssert("Size = 150", () => Precision.AlmostEquals(new Vector2(150), manualContainer.Child.Size));
|
AddAssert("Size = 150", () => Precision.AlmostEquals(new Vector2(150), manualContainer.Child.Size));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testFlowInstant()
|
private void testFlowInstant()
|
||||||
{
|
{
|
||||||
Box box2 = null;
|
Box box2 = null;
|
||||||
|
|
||||||
AddStep("Initialize flow test", () =>
|
AddStep("Initialize flow test", () =>
|
||||||
{
|
{
|
||||||
manualContainer.Child = new FillFlowContainer
|
manualContainer.Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Box { Size = new Vector2(150) },
|
new Box { Size = new Vector2(150) },
|
||||||
box2 = new Box { Size = new Vector2(150) }
|
box2 = new Box { Size = new Vector2(150) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Run to end", () => manualContainer.PerformUpdate(null));
|
AddStep("Run to end", () => manualContainer.PerformUpdate(null));
|
||||||
AddAssert("Box2 @ (150, 0)", () => Precision.AlmostEquals(new Vector2(150, 0), box2.Position));
|
AddAssert("Box2 @ (150, 0)", () => Precision.AlmostEquals(new Vector2(150, 0), box2.Position));
|
||||||
|
|
||||||
AddStep("Rewind", () => manualContainer.PerformUpdate(() => manualContainer.ApplyTransformsAt(-1, true)));
|
AddStep("Rewind", () => manualContainer.PerformUpdate(() => manualContainer.ApplyTransformsAt(-1, true)));
|
||||||
AddAssert("Box2 @ (150, 0)", () => Precision.AlmostEquals(new Vector2(150, 0), box2.Position));
|
AddAssert("Box2 @ (150, 0)", () => Precision.AlmostEquals(new Vector2(150, 0), box2.Position));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ManualUpdateSubTreeContainer : Container
|
private class ManualUpdateSubTreeContainer : Container
|
||||||
{
|
{
|
||||||
public override bool RemoveCompletedTransforms => false;
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
private Action onUpdateAfterChildren;
|
private Action onUpdateAfterChildren;
|
||||||
|
|
||||||
public ManualUpdateSubTreeContainer()
|
public ManualUpdateSubTreeContainer()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PerformUpdate(Action afterChildren)
|
public void PerformUpdate(Action afterChildren)
|
||||||
{
|
{
|
||||||
onUpdateAfterChildren = afterChildren;
|
onUpdateAfterChildren = afterChildren;
|
||||||
base.UpdateSubTree();
|
base.UpdateSubTree();
|
||||||
onUpdateAfterChildren = null;
|
onUpdateAfterChildren = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool UpdateSubTree() => false;
|
public override bool UpdateSubTree() => false;
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
onUpdateAfterChildren?.Invoke();
|
onUpdateAfterChildren?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +1,104 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseLocalisation : TestCase
|
public class TestCaseLocalisation : TestCase
|
||||||
{
|
{
|
||||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
private readonly LocalisationEngine engine; //keep a reference to avoid GC of the engine
|
private readonly LocalisationEngine engine; //keep a reference to avoid GC of the engine
|
||||||
|
|
||||||
public TestCaseLocalisation()
|
public TestCaseLocalisation()
|
||||||
{
|
{
|
||||||
var config = new FakeFrameworkConfigManager();
|
var config = new FakeFrameworkConfigManager();
|
||||||
engine = new LocalisationEngine(config);
|
engine = new LocalisationEngine(config);
|
||||||
|
|
||||||
engine.AddLanguage("en", new FakeStorage());
|
engine.AddLanguage("en", new FakeStorage());
|
||||||
engine.AddLanguage("zh-CHS", new FakeStorage());
|
engine.AddLanguage("zh-CHS", new FakeStorage());
|
||||||
engine.AddLanguage("ja", new FakeStorage());
|
engine.AddLanguage("ja", new FakeStorage());
|
||||||
|
|
||||||
Add(new FillFlowContainer<SpriteText>
|
Add(new FillFlowContainer<SpriteText>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 10),
|
Spacing = new Vector2(0, 10),
|
||||||
Padding = new MarginPadding(10),
|
Padding = new MarginPadding(10),
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "Not localisable",
|
Text = "Not localisable",
|
||||||
TextSize = 48,
|
TextSize = 48,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Current = engine.GetLocalisedString("localisable"),
|
Current = engine.GetLocalisedString("localisable"),
|
||||||
TextSize = 48,
|
TextSize = 48,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Current = engine.GetUnicodePreference("Unicode on", "Unicode off"),
|
Current = engine.GetUnicodePreference("Unicode on", "Unicode off"),
|
||||||
TextSize = 48,
|
TextSize = 48,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Current = engine.GetUnicodePreference(null, "I miss unicode"),
|
Current = engine.GetUnicodePreference(null, "I miss unicode"),
|
||||||
TextSize = 48,
|
TextSize = 48,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Current = engine.Format($"{DateTime.Now}"),
|
Current = engine.Format($"{DateTime.Now}"),
|
||||||
TextSize = 48,
|
TextSize = 48,
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("English", () => config.Set(FrameworkSetting.Locale, "en"));
|
AddStep("English", () => config.Set(FrameworkSetting.Locale, "en"));
|
||||||
AddStep("Japanese", () => config.Set(FrameworkSetting.Locale, "ja"));
|
AddStep("Japanese", () => config.Set(FrameworkSetting.Locale, "ja"));
|
||||||
AddStep("Simplified Chinese", () => config.Set(FrameworkSetting.Locale, "zh-CHS"));
|
AddStep("Simplified Chinese", () => config.Set(FrameworkSetting.Locale, "zh-CHS"));
|
||||||
AddToggleStep("ShowUnicode", b => config.Set(FrameworkSetting.ShowUnicode, b));
|
AddToggleStep("ShowUnicode", b => config.Set(FrameworkSetting.ShowUnicode, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeFrameworkConfigManager : FrameworkConfigManager
|
private class FakeFrameworkConfigManager : FrameworkConfigManager
|
||||||
{
|
{
|
||||||
protected override string Filename => null;
|
protected override string Filename => null;
|
||||||
|
|
||||||
public FakeFrameworkConfigManager() : base(null) { }
|
public FakeFrameworkConfigManager() : base(null) { }
|
||||||
|
|
||||||
protected override void InitialiseDefaults()
|
protected override void InitialiseDefaults()
|
||||||
{
|
{
|
||||||
Set(FrameworkSetting.Locale, "");
|
Set(FrameworkSetting.Locale, "");
|
||||||
Set(FrameworkSetting.ShowUnicode, false);
|
Set(FrameworkSetting.ShowUnicode, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeStorage : IResourceStore<string>
|
private class FakeStorage : IResourceStore<string>
|
||||||
{
|
{
|
||||||
public string Get(string name) => $"{name} in {CultureInfo.CurrentCulture.EnglishName}";
|
public string Get(string name) => $"{name} in {CultureInfo.CurrentCulture.EnglishName}";
|
||||||
public Stream GetStream(string name)
|
public Stream GetStream(string name)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,458 +1,458 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseMasking : TestCase
|
public class TestCaseMasking : TestCase
|
||||||
{
|
{
|
||||||
protected Container TestContainer;
|
protected Container TestContainer;
|
||||||
|
|
||||||
public TestCaseMasking()
|
public TestCaseMasking()
|
||||||
{
|
{
|
||||||
Add(TestContainer = new Container
|
Add(TestContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
});
|
});
|
||||||
|
|
||||||
string[] testNames =
|
string[] testNames =
|
||||||
{
|
{
|
||||||
@"Round corner masking",
|
@"Round corner masking",
|
||||||
@"Round corner AABB 1",
|
@"Round corner AABB 1",
|
||||||
@"Round corner AABB 2",
|
@"Round corner AABB 2",
|
||||||
@"Round corner AABB 3",
|
@"Round corner AABB 3",
|
||||||
@"Edge/border blurriness",
|
@"Edge/border blurriness",
|
||||||
@"Nested masking",
|
@"Nested masking",
|
||||||
@"Rounded corner input"
|
@"Rounded corner input"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < testNames.Length; i++)
|
for (int i = 0; i < testNames.Length; i++)
|
||||||
{
|
{
|
||||||
int test = i;
|
int test = i;
|
||||||
AddStep(testNames[i], delegate { loadTest(test); });
|
AddStep(testNames[i], delegate { loadTest(test); });
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTest(0);
|
loadTest(0);
|
||||||
addCrosshair();
|
addCrosshair();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCrosshair()
|
private void addCrosshair()
|
||||||
{
|
{
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Size = new Vector2(22, 4),
|
Size = new Vector2(22, 4),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Size = new Vector2(4, 22),
|
Size = new Vector2(4, 22),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.WhiteSmoke,
|
Colour = Color4.WhiteSmoke,
|
||||||
Size = new Vector2(20, 2),
|
Size = new Vector2(20, 2),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.WhiteSmoke,
|
Colour = Color4.WhiteSmoke,
|
||||||
Size = new Vector2(2, 20),
|
Size = new Vector2(2, 20),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTest(int testType)
|
private void loadTest(int testType)
|
||||||
{
|
{
|
||||||
TestContainer.Clear();
|
TestContainer.Clear();
|
||||||
|
|
||||||
switch (testType)
|
switch (testType)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
Container box;
|
Container box;
|
||||||
TestContainer.Add(box = new InfofulBoxAutoSize
|
TestContainer.Add(box = new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 100,
|
CornerRadius = 100,
|
||||||
BorderColour = Color4.Aquamarine,
|
BorderColour = Color4.Aquamarine,
|
||||||
BorderThickness = 3,
|
BorderThickness = 3,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Shadow,
|
Type = EdgeEffectType.Shadow,
|
||||||
Radius = 100,
|
Radius = 100,
|
||||||
Colour = new Color4(0, 50, 100, 200),
|
Colour = new Color4(0, 50, 100, 200),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
box.Add(box = new InfofulBox
|
box.Add(box = new InfofulBox
|
||||||
{
|
{
|
||||||
Size = new Vector2(250, 250),
|
Size = new Vector2(250, 250),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.DarkSeaGreen,
|
Colour = Color4.DarkSeaGreen,
|
||||||
});
|
});
|
||||||
|
|
||||||
box.OnUpdate += delegate { box.Rotation += 0.05f; };
|
box.OnUpdate += delegate { box.Rotation += 0.05f; };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
Container box;
|
Container box;
|
||||||
TestContainer.Add(new InfofulBoxAutoSize
|
TestContainer.Add(new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
box = new InfofulBox
|
box = new InfofulBox
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 100,
|
CornerRadius = 100,
|
||||||
Size = new Vector2(400, 400),
|
Size = new Vector2(400, 400),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.DarkSeaGreen,
|
Colour = Color4.DarkSeaGreen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
box.OnUpdate += delegate
|
box.OnUpdate += delegate
|
||||||
{
|
{
|
||||||
box.Rotation += 0.05f;
|
box.Rotation += 0.05f;
|
||||||
box.CornerRadius = 100 + 100 * (float)Math.Sin(box.Rotation * 0.01);
|
box.CornerRadius = 100 + 100 * (float)Math.Sin(box.Rotation * 0.01);
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
Container box;
|
Container box;
|
||||||
TestContainer.Add(new InfofulBoxAutoSize
|
TestContainer.Add(new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
box = new InfofulBox
|
box = new InfofulBox
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 25,
|
CornerRadius = 25,
|
||||||
Shear = new Vector2(0.5f, 0),
|
Shear = new Vector2(0.5f, 0),
|
||||||
Size = new Vector2(150, 150),
|
Size = new Vector2(150, 150),
|
||||||
Scale = new Vector2(2.5f, 1.5f),
|
Scale = new Vector2(2.5f, 1.5f),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.DarkSeaGreen,
|
Colour = Color4.DarkSeaGreen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
box.OnUpdate += delegate { box.Rotation += 0.05f; };
|
box.OnUpdate += delegate { box.Rotation += 0.05f; };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
Color4 glowColour = Color4.Aquamarine;
|
Color4 glowColour = Color4.Aquamarine;
|
||||||
glowColour.A = 0.5f;
|
glowColour.A = 0.5f;
|
||||||
|
|
||||||
Container box1;
|
Container box1;
|
||||||
Container box2;
|
Container box2;
|
||||||
|
|
||||||
TestContainer.Add(new InfofulBoxAutoSize
|
TestContainer.Add(new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 100,
|
Radius = 100,
|
||||||
Roundness = 50,
|
Roundness = 50,
|
||||||
Colour = glowColour,
|
Colour = glowColour,
|
||||||
},
|
},
|
||||||
BorderColour = Color4.Aquamarine,
|
BorderColour = Color4.Aquamarine,
|
||||||
BorderThickness = 3,
|
BorderThickness = 3,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
box1 = new InfofulBoxAutoSize
|
box1 = new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 25,
|
CornerRadius = 25,
|
||||||
Shear = new Vector2(0.5f, 0),
|
Shear = new Vector2(0.5f, 0),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.DarkSeaGreen,
|
Colour = Color4.DarkSeaGreen,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
box2 = new InfofulBox
|
box2 = new InfofulBox
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 25,
|
CornerRadius = 25,
|
||||||
Shear = new Vector2(0.25f, 0.25f),
|
Shear = new Vector2(0.25f, 0.25f),
|
||||||
Size = new Vector2(100, 200),
|
Size = new Vector2(100, 200),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
box1.OnUpdate += delegate { box1.Rotation += 0.07f; };
|
box1.OnUpdate += delegate { box1.Rotation += 0.07f; };
|
||||||
box2.OnUpdate += delegate { box2.Rotation -= 0.15f; };
|
box2.OnUpdate += delegate { box2.Rotation -= 0.15f; };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
Func<float, Drawable> createMaskingBox = delegate (float scale)
|
Func<float, Drawable> createMaskingBox = delegate (float scale)
|
||||||
{
|
{
|
||||||
float size = 200 / scale;
|
float size = 200 / scale;
|
||||||
return new Container
|
return new Container
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 25 / scale,
|
CornerRadius = 25 / scale,
|
||||||
BorderThickness = 12.5f / scale,
|
BorderThickness = 12.5f / scale,
|
||||||
BorderColour = Color4.Red,
|
BorderColour = Color4.Red,
|
||||||
Size = new Vector2(size),
|
Size = new Vector2(size),
|
||||||
Scale = new Vector2(scale),
|
Scale = new Vector2(scale),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = @"Size: " + size + ", Scale: " + scale,
|
Text = @"Size: " + size + ", Scale: " + scale,
|
||||||
TextSize = 20 / scale,
|
TextSize = 20 / scale,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
TestContainer.Add(new FillFlowContainer
|
TestContainer.Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[] { createMaskingBox(100) }
|
Children = new[] { createMaskingBox(100) }
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[] { createMaskingBox(10) }
|
Children = new[] { createMaskingBox(10) }
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[] { createMaskingBox(1) }
|
Children = new[] { createMaskingBox(1) }
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[] { createMaskingBox(0.1f) }
|
Children = new[] { createMaskingBox(0.1f) }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
TestContainer.Add(new Container
|
TestContainer.Add(new Container
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 100f,
|
CornerRadius = 100f,
|
||||||
BorderThickness = 50f,
|
BorderThickness = 50f,
|
||||||
BorderColour = Color4.Red,
|
BorderColour = Color4.Red,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(1.5f),
|
Size = new Vector2(1.5f),
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
{
|
{
|
||||||
TestContainer.Add(new FillFlowContainer
|
TestContainer.Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(0, 10),
|
Spacing = new Vector2(0, 10),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = $"None of the folowing {nameof(CircularContainer)}s should trigger until the white part is hovered"
|
Text = $"None of the folowing {nameof(CircularContainer)}s should trigger until the white part is hovered"
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(0, 2),
|
Spacing = new Vector2(0, 2),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "No masking"
|
Text = "No masking"
|
||||||
},
|
},
|
||||||
new CircularContainerWithInput
|
new CircularContainerWithInput
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Red
|
Colour = Color4.Red
|
||||||
},
|
},
|
||||||
new CircularContainer
|
new CircularContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Spacing = new Vector2(0, 2),
|
Spacing = new Vector2(0, 2),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "With masking"
|
Text = "With masking"
|
||||||
},
|
},
|
||||||
new CircularContainerWithInput
|
new CircularContainerWithInput
|
||||||
{
|
{
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Red
|
Colour = Color4.Red
|
||||||
},
|
},
|
||||||
new CircularContainer
|
new CircularContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//if (toggleDebugAutosize.State)
|
//if (toggleDebugAutosize.State)
|
||||||
// testContainer.Children.FindAll(c => c.HasAutosizeChildren).ForEach(c => c.AutoSizeDebug = true);
|
// testContainer.Children.FindAll(c => c.HasAutosizeChildren).ForEach(c => c.AutoSizeDebug = true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CircularContainerWithInput : CircularContainer
|
private class CircularContainerWithInput : CircularContainer
|
||||||
{
|
{
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
this.ScaleTo(1.2f, 100);
|
this.ScaleTo(1.2f, 100);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
this.ScaleTo(1f, 100);
|
this.ScaleTo(1f, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,80 +1,80 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseNestedHover : TestCase
|
public class TestCaseNestedHover : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseNestedHover()
|
public TestCaseNestedHover()
|
||||||
{
|
{
|
||||||
HoverBox box1;
|
HoverBox box1;
|
||||||
Add(box1 = new HoverBox(Color4.Gray, Color4.White)
|
Add(box1 = new HoverBox(Color4.Gray, Color4.White)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(300, 300)
|
Size = new Vector2(300, 300)
|
||||||
});
|
});
|
||||||
|
|
||||||
HoverBox box2;
|
HoverBox box2;
|
||||||
box1.Add(box2 = new HoverBox(Color4.Pink, Color4.Red)
|
box1.Add(box2 = new HoverBox(Color4.Pink, Color4.Red)
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(0.2f, 0.2f),
|
Position = new Vector2(0.2f, 0.2f),
|
||||||
Size = new Vector2(0.6f, 0.6f)
|
Size = new Vector2(0.6f, 0.6f)
|
||||||
});
|
});
|
||||||
|
|
||||||
box2.Add(new HoverBox(Color4.LightBlue, Color4.Blue, false)
|
box2.Add(new HoverBox(Color4.LightBlue, Color4.Blue, false)
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(0.2f, 0.2f),
|
Position = new Vector2(0.2f, 0.2f),
|
||||||
Size = new Vector2(0.6f, 0.6f)
|
Size = new Vector2(0.6f, 0.6f)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HoverBox : Container
|
private class HoverBox : Container
|
||||||
{
|
{
|
||||||
private readonly Color4 normalColour;
|
private readonly Color4 normalColour;
|
||||||
private readonly Color4 hoveredColour;
|
private readonly Color4 hoveredColour;
|
||||||
|
|
||||||
private readonly Box box;
|
private readonly Box box;
|
||||||
private readonly bool propagateHover;
|
private readonly bool propagateHover;
|
||||||
|
|
||||||
public HoverBox(Color4 normalColour, Color4 hoveredColour, bool propagateHover = true)
|
public HoverBox(Color4 normalColour, Color4 hoveredColour, bool propagateHover = true)
|
||||||
{
|
{
|
||||||
this.normalColour = normalColour;
|
this.normalColour = normalColour;
|
||||||
this.hoveredColour = hoveredColour;
|
this.hoveredColour = hoveredColour;
|
||||||
this.propagateHover = propagateHover;
|
this.propagateHover = propagateHover;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
box = new Box
|
box = new Box
|
||||||
{
|
{
|
||||||
Colour = normalColour,
|
Colour = normalColour,
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
box.Colour = hoveredColour;
|
box.Colour = hoveredColour;
|
||||||
return !propagateHover;
|
return !propagateHover;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
box.Colour = normalColour;
|
box.Colour = normalColour;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,493 +1,493 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Testing.Input;
|
using osu.Framework.Testing.Input;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Input;
|
using OpenTK.Input;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseNestedMenus : TestCase
|
public class TestCaseNestedMenus : TestCase
|
||||||
{
|
{
|
||||||
private const int max_depth = 5;
|
private const int max_depth = 5;
|
||||||
private const int max_count = 5;
|
private const int max_count = 5;
|
||||||
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Menu) };
|
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(Menu) };
|
||||||
|
|
||||||
private Random rng;
|
private Random rng;
|
||||||
|
|
||||||
private ManualInputManager inputManager;
|
private ManualInputManager inputManager;
|
||||||
private MenuStructure menus;
|
private MenuStructure menus;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
rng = new Random(1337);
|
rng = new Random(1337);
|
||||||
|
|
||||||
Menu menu;
|
Menu menu;
|
||||||
Add(inputManager = new ManualInputManager
|
Add(inputManager = new ManualInputManager
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new CursorContainer(),
|
new CursorContainer(),
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = menu = createMenu()
|
Child = menu = createMenu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
menus = new MenuStructure(menu);
|
menus = new MenuStructure(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Menu createMenu() => new ClickOpenMenu(TimePerAction)
|
private Menu createMenu() => new ClickOpenMenu(TimePerAction)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Items = new[]
|
Items = new[]
|
||||||
{
|
{
|
||||||
generateRandomMenuItem("First"),
|
generateRandomMenuItem("First"),
|
||||||
generateRandomMenuItem("Second"),
|
generateRandomMenuItem("Second"),
|
||||||
generateRandomMenuItem("Third"),
|
generateRandomMenuItem("Third"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private class ClickOpenMenu : Menu
|
private class ClickOpenMenu : Menu
|
||||||
{
|
{
|
||||||
protected override Menu CreateSubMenu() => new ClickOpenMenu(HoverOpenDelay, false);
|
protected override Menu CreateSubMenu() => new ClickOpenMenu(HoverOpenDelay, false);
|
||||||
|
|
||||||
public ClickOpenMenu(double timePerAction, bool topLevel = true) : base(Direction.Vertical, topLevel)
|
public ClickOpenMenu(double timePerAction, bool topLevel = true) : base(Direction.Vertical, topLevel)
|
||||||
{
|
{
|
||||||
HoverOpenDelay = timePerAction;
|
HoverOpenDelay = timePerAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Test Cases
|
#region Test Cases
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if the <see cref="Menu"/> respects <see cref="Menu.TopLevelMenu"/> = true, by not alowing it to be closed
|
/// Tests if the <see cref="Menu"/> respects <see cref="Menu.TopLevelMenu"/> = true, by not alowing it to be closed
|
||||||
/// when a click happens outside the <see cref="Menu"/>.
|
/// when a click happens outside the <see cref="Menu"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAlwaysOpen()
|
public void TestAlwaysOpen()
|
||||||
{
|
{
|
||||||
AddStep("Click outside", () => inputManager.Click(MouseButton.Left));
|
AddStep("Click outside", () => inputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Check AlwaysOpen = true", () => menus.GetSubMenu(0).State == MenuState.Open);
|
AddAssert("Check AlwaysOpen = true", () => menus.GetSubMenu(0).State == MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if the hover state on <see cref="Menu.DrawableMenuItem"/>s is valid.
|
/// Tests if the hover state on <see cref="Menu.DrawableMenuItem"/>s is valid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHoverState()
|
public void TestHoverState()
|
||||||
{
|
{
|
||||||
AddAssert("Check submenu closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
AddAssert("Check submenu closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetMenuItems()[0]));
|
||||||
AddAssert("Check item hovered", () => menus.GetMenuItems()[0].IsHovered);
|
AddAssert("Check item hovered", () => menus.GetMenuItems()[0].IsHovered);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if the <see cref="Menu"/> respects <see cref="Menu.TopLevelMenu"/> = true.
|
/// Tests if the <see cref="Menu"/> respects <see cref="Menu.TopLevelMenu"/> = true.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestTopLevelMenu()
|
public void TestTopLevelMenu()
|
||||||
{
|
{
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(0).GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(0).GetMenuItems()[0]));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
||||||
AddStep("Click item", () => inputManager.Click(MouseButton.Left));
|
AddStep("Click item", () => inputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if clicking once on a menu that has <see cref="Menu.TopLevelMenu"/> opens it, and clicking a second time
|
/// Tests if clicking once on a menu that has <see cref="Menu.TopLevelMenu"/> opens it, and clicking a second time
|
||||||
/// closes it.
|
/// closes it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDoubleClick()
|
public void TestDoubleClick()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 0));
|
AddStep("Click item", () => clickItem(0, 0));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
AddStep("Click item", () => clickItem(0, 0));
|
AddStep("Click item", () => clickItem(0, 0));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether click on <see cref="Menu.DrawableMenuItem"/>s causes sub-menus to instantly appear.
|
/// Tests whether click on <see cref="Menu.DrawableMenuItem"/>s causes sub-menus to instantly appear.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestInstantOpen()
|
public void TestInstantOpen()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
AddStep("Click item", () => clickItem(1, 0));
|
AddStep("Click item", () => clickItem(1, 0));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if clicking on an item that has no sub-menu causes the menu to close.
|
/// Tests if clicking on an item that has no sub-menu causes the menu to close.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestActionClick()
|
public void TestActionClick()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 0));
|
AddStep("Click item", () => clickItem(0, 0));
|
||||||
AddStep("Click item", () => clickItem(1, 0));
|
AddStep("Click item", () => clickItem(1, 0));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(1)?.State != MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if hovering over menu items respects the <see cref="Menu.HoverOpenDelay"/>.
|
/// Tests if hovering over menu items respects the <see cref="Menu.HoverOpenDelay"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHoverOpen()
|
public void TestHoverOpen()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[0]));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(2).GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(2).GetMenuItems()[0]));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(3)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(3)?.State != MenuState.Open);
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(3).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(3).State == MenuState.Open);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests if hovering over a different item on the main <see cref="Menu"/> will instantly open another menu
|
/// Tests if hovering over a different item on the main <see cref="Menu"/> will instantly open another menu
|
||||||
/// and correctly changes the sub-menu items to the new items from the hovered item.
|
/// and correctly changes the sub-menu items to the new items from the hovered item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHoverChange()
|
public void TestHoverChange()
|
||||||
{
|
{
|
||||||
IReadOnlyList<MenuItem> currentItems = null;
|
IReadOnlyList<MenuItem> currentItems = null;
|
||||||
AddStep("Click item", () =>
|
AddStep("Click item", () =>
|
||||||
{
|
{
|
||||||
clickItem(0, 0);
|
clickItem(0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("Get items", () =>
|
AddStep("Get items", () =>
|
||||||
{
|
{
|
||||||
currentItems = menus.GetSubMenu(1).Items;
|
currentItems = menus.GetSubMenu(1).Items;
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(0).GetMenuItems()[1]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(0).GetMenuItems()[1]));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
|
|
||||||
AddAssert("Check new items", () => !menus.GetSubMenu(1).Items.SequenceEqual(currentItems));
|
AddAssert("Check new items", () => !menus.GetSubMenu(1).Items.SequenceEqual(currentItems));
|
||||||
AddAssert("Check closed", () =>
|
AddAssert("Check closed", () =>
|
||||||
{
|
{
|
||||||
int currentSubMenu = 3;
|
int currentSubMenu = 3;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var subMenu = menus.GetSubMenu(currentSubMenu);
|
var subMenu = menus.GetSubMenu(currentSubMenu);
|
||||||
if (subMenu == null)
|
if (subMenu == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (subMenu.State == MenuState.Open)
|
if (subMenu.State == MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
currentSubMenu++;
|
currentSubMenu++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether hovering over a different item on a sub-menu opens a new sub-menu in a delayed fashion
|
/// Tests whether hovering over a different item on a sub-menu opens a new sub-menu in a delayed fashion
|
||||||
/// and correctly changes the sub-menu items to the new items from the hovered item.
|
/// and correctly changes the sub-menu items to the new items from the hovered item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDelayedHoverChange()
|
public void TestDelayedHoverChange()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 2));
|
AddStep("Click item", () => clickItem(0, 2));
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[0]));
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
||||||
|
|
||||||
AddStep("Hover item", () =>
|
AddStep("Hover item", () =>
|
||||||
{
|
{
|
||||||
inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[1]);
|
inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
AddAssert("Check closed", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
||||||
|
|
||||||
AddAssert("Check closed", () =>
|
AddAssert("Check closed", () =>
|
||||||
{
|
{
|
||||||
int currentSubMenu = 3;
|
int currentSubMenu = 3;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var subMenu = menus.GetSubMenu(currentSubMenu);
|
var subMenu = menus.GetSubMenu(currentSubMenu);
|
||||||
if (subMenu == null)
|
if (subMenu == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (subMenu.State == MenuState.Open)
|
if (subMenu.State == MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
currentSubMenu++;
|
currentSubMenu++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether clicking on <see cref="Menu"/>s that have opened sub-menus don't close the sub-menus.
|
/// Tests whether clicking on <see cref="Menu"/>s that have opened sub-menus don't close the sub-menus.
|
||||||
/// Then tests hovering in reverse order to make sure only the lower level menus close.
|
/// Then tests hovering in reverse order to make sure only the lower level menus close.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMenuClicksDontClose()
|
public void TestMenuClicksDontClose()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
AddStep("Click item", () => clickItem(1, 0));
|
AddStep("Click item", () => clickItem(1, 0));
|
||||||
AddStep("Click item", () => clickItem(2, 0));
|
AddStep("Click item", () => clickItem(2, 0));
|
||||||
AddStep("Click item", () => clickItem(3, 0));
|
AddStep("Click item", () => clickItem(3, 0));
|
||||||
|
|
||||||
for (int i = 3; i >= 1; i--)
|
for (int i = 3; i >= 1; i--)
|
||||||
{
|
{
|
||||||
int menuIndex = i;
|
int menuIndex = i;
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(menuIndex).GetMenuItems()[0]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(menuIndex).GetMenuItems()[0]));
|
||||||
AddAssert("Check submenu open", () => menus.GetSubMenu(menuIndex + 1).State == MenuState.Open);
|
AddAssert("Check submenu open", () => menus.GetSubMenu(menuIndex + 1).State == MenuState.Open);
|
||||||
AddStep("Click item", () => inputManager.Click(MouseButton.Left));
|
AddStep("Click item", () => inputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Check all open", () =>
|
AddAssert("Check all open", () =>
|
||||||
{
|
{
|
||||||
for (int j = 0; j <= menuIndex; j++)
|
for (int j = 0; j <= menuIndex; j++)
|
||||||
{
|
{
|
||||||
int menuIndex2 = j;
|
int menuIndex2 = j;
|
||||||
if (menus.GetSubMenu(menuIndex2)?.State != MenuState.Open)
|
if (menus.GetSubMenu(menuIndex2)?.State != MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether clicking on the <see cref="Menu"/> that has <see cref="Menu.TopLevelMenu"/> closes all sub menus.
|
/// Tests whether clicking on the <see cref="Menu"/> that has <see cref="Menu.TopLevelMenu"/> closes all sub menus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestMenuClickClosesSubMenus()
|
public void TestMenuClickClosesSubMenus()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
AddStep("Click item", () => clickItem(1, 0));
|
AddStep("Click item", () => clickItem(1, 0));
|
||||||
AddStep("Click item", () => clickItem(2, 0));
|
AddStep("Click item", () => clickItem(2, 0));
|
||||||
AddStep("Click item", () => clickItem(3, 0));
|
AddStep("Click item", () => clickItem(3, 0));
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
|
|
||||||
AddAssert("Check submenus closed", () =>
|
AddAssert("Check submenus closed", () =>
|
||||||
{
|
{
|
||||||
for (int j = 1; j <= 3; j++)
|
for (int j = 1; j <= 3; j++)
|
||||||
{
|
{
|
||||||
int menuIndex2 = j;
|
int menuIndex2 = j;
|
||||||
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether clicking on an action in a sub-menu closes all <see cref="Menu"/>s.
|
/// Tests whether clicking on an action in a sub-menu closes all <see cref="Menu"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestActionClickClosesMenus()
|
public void TestActionClickClosesMenus()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 1));
|
AddStep("Click item", () => clickItem(0, 1));
|
||||||
AddStep("Click item", () => clickItem(1, 0));
|
AddStep("Click item", () => clickItem(1, 0));
|
||||||
AddStep("Click item", () => clickItem(2, 0));
|
AddStep("Click item", () => clickItem(2, 0));
|
||||||
AddStep("Click item", () => clickItem(3, 0));
|
AddStep("Click item", () => clickItem(3, 0));
|
||||||
AddStep("Click item", () => clickItem(4, 0));
|
AddStep("Click item", () => clickItem(4, 0));
|
||||||
|
|
||||||
AddAssert("Check submenus closed", () =>
|
AddAssert("Check submenus closed", () =>
|
||||||
{
|
{
|
||||||
for (int j = 1; j <= 3; j++)
|
for (int j = 1; j <= 3; j++)
|
||||||
{
|
{
|
||||||
int menuIndex2 = j;
|
int menuIndex2 = j;
|
||||||
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tests whether clicking outside the <see cref="Menu"/> structure closes all sub-menus.
|
/// Tests whether clicking outside the <see cref="Menu"/> structure closes all sub-menus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hoverPrevious">Whether the previous menu should first be hovered before clicking outside.</param>
|
/// <param name="hoverPrevious">Whether the previous menu should first be hovered before clicking outside.</param>
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
public void TestClickingOutsideClosesMenus(bool hoverPrevious)
|
public void TestClickingOutsideClosesMenus(bool hoverPrevious)
|
||||||
{
|
{
|
||||||
for (int i = 0; i <= 3; i++)
|
for (int i = 0; i <= 3; i++)
|
||||||
{
|
{
|
||||||
int i2 = i;
|
int i2 = i;
|
||||||
|
|
||||||
for (int j = 0; j <= i; j++)
|
for (int j = 0; j <= i; j++)
|
||||||
{
|
{
|
||||||
int menuToOpen = j;
|
int menuToOpen = j;
|
||||||
int itemToOpen = menuToOpen == 0 ? 1 : 0;
|
int itemToOpen = menuToOpen == 0 ? 1 : 0;
|
||||||
AddStep("Click item", () => clickItem(menuToOpen, itemToOpen));
|
AddStep("Click item", () => clickItem(menuToOpen, itemToOpen));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hoverPrevious && i > 0)
|
if (hoverPrevious && i > 0)
|
||||||
AddStep("Hover previous", () => inputManager.MoveMouseTo(menus.GetSubStructure(i2 - 1).GetMenuItems()[i2 > 1 ? 0 : 1]));
|
AddStep("Hover previous", () => inputManager.MoveMouseTo(menus.GetSubStructure(i2 - 1).GetMenuItems()[i2 > 1 ? 0 : 1]));
|
||||||
|
|
||||||
AddStep("Remove hover", () => inputManager.MoveMouseTo(Vector2.Zero));
|
AddStep("Remove hover", () => inputManager.MoveMouseTo(Vector2.Zero));
|
||||||
AddStep("Click outside", () => inputManager.Click(MouseButton.Left));
|
AddStep("Click outside", () => inputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Check submenus closed", () =>
|
AddAssert("Check submenus closed", () =>
|
||||||
{
|
{
|
||||||
for (int j = 1; j <= i2 + 1; j++)
|
for (int j = 1; j <= i2 + 1; j++)
|
||||||
{
|
{
|
||||||
int menuIndex2 = j;
|
int menuIndex2 = j;
|
||||||
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
if (menus.GetSubMenu(menuIndex2).State == MenuState.Open)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens some menus and then changes the selected item.
|
/// Opens some menus and then changes the selected item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSelectedState()
|
public void TestSelectedState()
|
||||||
{
|
{
|
||||||
AddStep("Click item", () => clickItem(0, 2));
|
AddStep("Click item", () => clickItem(0, 2));
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(1).State == MenuState.Open);
|
||||||
|
|
||||||
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[1]));
|
AddStep("Hover item", () => inputManager.MoveMouseTo(menus.GetSubStructure(1).GetMenuItems()[1]));
|
||||||
AddAssert("Check closed 1", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
AddAssert("Check closed 1", () => menus.GetSubMenu(2)?.State != MenuState.Open);
|
||||||
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
AddAssert("Check open", () => menus.GetSubMenu(2).State == MenuState.Open);
|
||||||
AddAssert("Check selected index 1", () => menus.GetSubStructure(1).GetSelectedIndex() == 1);
|
AddAssert("Check selected index 1", () => menus.GetSubStructure(1).GetSelectedIndex() == 1);
|
||||||
|
|
||||||
AddStep("Change selection", () => menus.GetSubStructure(1).SetSelectedState(0, MenuItemState.Selected));
|
AddStep("Change selection", () => menus.GetSubStructure(1).SetSelectedState(0, MenuItemState.Selected));
|
||||||
AddAssert("Check selected index", () => menus.GetSubStructure(1).GetSelectedIndex() == 0);
|
AddAssert("Check selected index", () => menus.GetSubStructure(1).GetSelectedIndex() == 0);
|
||||||
|
|
||||||
AddStep("Change selection", () => menus.GetSubStructure(1).SetSelectedState(2, MenuItemState.Selected));
|
AddStep("Change selection", () => menus.GetSubStructure(1).SetSelectedState(2, MenuItemState.Selected));
|
||||||
AddAssert("Check selected index 2", () => menus.GetSubStructure(1).GetSelectedIndex() == 2);
|
AddAssert("Check selected index 2", () => menus.GetSubStructure(1).GetSelectedIndex() == 2);
|
||||||
|
|
||||||
AddStep("Close menus", () => menus.GetSubMenu(0).Close());
|
AddStep("Close menus", () => menus.GetSubMenu(0).Close());
|
||||||
AddAssert("Check selected index 4", () => menus.GetSubStructure(1).GetSelectedIndex() == -1);
|
AddAssert("Check selected index 4", () => menus.GetSubStructure(1).GetSelectedIndex() == -1);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Click an item in a menu.
|
/// Click an item in a menu.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="menuIndex">The level of menu our click targets.</param>
|
/// <param name="menuIndex">The level of menu our click targets.</param>
|
||||||
/// <param name="itemIndex">The item to click in the menu.</param>
|
/// <param name="itemIndex">The item to click in the menu.</param>
|
||||||
private void clickItem(int menuIndex, int itemIndex)
|
private void clickItem(int menuIndex, int itemIndex)
|
||||||
{
|
{
|
||||||
inputManager.MoveMouseTo(menus.GetSubStructure(menuIndex).GetMenuItems()[itemIndex]);
|
inputManager.MoveMouseTo(menus.GetSubStructure(menuIndex).GetMenuItems()[itemIndex]);
|
||||||
inputManager.Click(MouseButton.Left);
|
inputManager.Click(MouseButton.Left);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MenuItem generateRandomMenuItem(string name = "Menu Item", int currDepth = 1)
|
private MenuItem generateRandomMenuItem(string name = "Menu Item", int currDepth = 1)
|
||||||
{
|
{
|
||||||
var item = new MenuItem(name);
|
var item = new MenuItem(name);
|
||||||
|
|
||||||
if (currDepth == max_depth)
|
if (currDepth == max_depth)
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
int subCount = rng.Next(0, max_count);
|
int subCount = rng.Next(0, max_count);
|
||||||
var subItems = new List<MenuItem>();
|
var subItems = new List<MenuItem>();
|
||||||
for (int i = 0; i < subCount; i++)
|
for (int i = 0; i < subCount; i++)
|
||||||
subItems.Add(generateRandomMenuItem(item.Text + $" #{i + 1}", currDepth + 1));
|
subItems.Add(generateRandomMenuItem(item.Text + $" #{i + 1}", currDepth + 1));
|
||||||
|
|
||||||
item.Items = subItems;
|
item.Items = subItems;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper class used to retrieve various internal properties/items from a <see cref="Menu"/>.
|
/// Helper class used to retrieve various internal properties/items from a <see cref="Menu"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class MenuStructure
|
private class MenuStructure
|
||||||
{
|
{
|
||||||
private readonly Menu menu;
|
private readonly Menu menu;
|
||||||
|
|
||||||
public MenuStructure(Menu menu)
|
public MenuStructure(Menu menu)
|
||||||
{
|
{
|
||||||
this.menu = menu;
|
this.menu = menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the <see cref="Menu.DrawableMenuItem"/>s of the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.
|
/// Retrieves the <see cref="Menu.DrawableMenuItem"/>s of the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<Drawable> GetMenuItems()
|
public IReadOnlyList<Drawable> GetMenuItems()
|
||||||
{
|
{
|
||||||
var contents = (CompositeDrawable)menu.InternalChildren[0];
|
var contents = (CompositeDrawable)menu.InternalChildren[0];
|
||||||
var contentContainer = (CompositeDrawable)contents.InternalChildren[1];
|
var contentContainer = (CompositeDrawable)contents.InternalChildren[1];
|
||||||
return ((CompositeDrawable)((CompositeDrawable)contentContainer.InternalChildren[0]).InternalChildren[0]).InternalChildren;
|
return ((CompositeDrawable)((CompositeDrawable)contentContainer.InternalChildren[0]).InternalChildren[0]).InternalChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds the <see cref="Menu.DrawableMenuItem"/> index in the <see cref="Menu"/> represented by this <see cref="MenuStructure"/> that
|
/// Finds the <see cref="Menu.DrawableMenuItem"/> index in the <see cref="Menu"/> represented by this <see cref="MenuStructure"/> that
|
||||||
/// has <see cref="Menu.DrawableMenuItem.State"/> set to <see cref="MenuItemState.Selected"/>.
|
/// has <see cref="Menu.DrawableMenuItem.State"/> set to <see cref="MenuItemState.Selected"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int GetSelectedIndex()
|
public int GetSelectedIndex()
|
||||||
{
|
{
|
||||||
var items = GetMenuItems();
|
var items = GetMenuItems();
|
||||||
|
|
||||||
for (int i = 0; i < items.Count; i++)
|
for (int i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
var state = (MenuItemState)(items[i]?.GetType().GetProperty("State")?.GetValue(items[i]) ?? MenuItemState.NotSelected);
|
var state = (MenuItemState)(items[i]?.GetType().GetProperty("State")?.GetValue(items[i]) ?? MenuItemState.NotSelected);
|
||||||
if (state == MenuItemState.Selected)
|
if (state == MenuItemState.Selected)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the <see cref="Menu.DrawableMenuItem"/> <see cref="Menu.DrawableMenuItem.State"/> at the specified index to a specified state.
|
/// Sets the <see cref="Menu.DrawableMenuItem"/> <see cref="Menu.DrawableMenuItem.State"/> at the specified index to a specified state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The index of the <see cref="Menu.DrawableMenuItem"/> to set the state of.</param>
|
/// <param name="index">The index of the <see cref="Menu.DrawableMenuItem"/> to set the state of.</param>
|
||||||
/// <param name="state">The state to be set.</param>
|
/// <param name="state">The state to be set.</param>
|
||||||
public void SetSelectedState(int index, MenuItemState state)
|
public void SetSelectedState(int index, MenuItemState state)
|
||||||
{
|
{
|
||||||
var item = GetMenuItems()[index];
|
var item = GetMenuItems()[index];
|
||||||
item.GetType().GetProperty("State")?.SetValue(item, state);
|
item.GetType().GetProperty("State")?.SetValue(item, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the sub-<see cref="Menu"/> at an index-offset from the current <see cref="Menu"/>.
|
/// Retrieves the sub-<see cref="Menu"/> at an index-offset from the current <see cref="Menu"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The sub-<see cref="Menu"/> index. An index of 0 is the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.</param>
|
/// <param name="index">The sub-<see cref="Menu"/> index. An index of 0 is the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.</param>
|
||||||
public Menu GetSubMenu(int index)
|
public Menu GetSubMenu(int index)
|
||||||
{
|
{
|
||||||
var currentMenu = menu;
|
var currentMenu = menu;
|
||||||
for (int i = 0; i < index; i++)
|
for (int i = 0; i < index; i++)
|
||||||
{
|
{
|
||||||
if (currentMenu == null)
|
if (currentMenu == null)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var container = (CompositeDrawable)currentMenu.InternalChildren[1];
|
var container = (CompositeDrawable)currentMenu.InternalChildren[1];
|
||||||
currentMenu = (container.InternalChildren.Count > 0 ? container.InternalChildren[0] : null) as Menu;
|
currentMenu = (container.InternalChildren.Count > 0 ? container.InternalChildren[0] : null) as Menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentMenu;
|
return currentMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a new <see cref="MenuStructure"/> for the a sub-<see cref="Menu"/>.
|
/// Generates a new <see cref="MenuStructure"/> for the a sub-<see cref="Menu"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="index">The sub-<see cref="Menu"/> index to generate the <see cref="MenuStructure"/> for. An index of 0 is the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.</param>
|
/// <param name="index">The sub-<see cref="Menu"/> index to generate the <see cref="MenuStructure"/> for. An index of 0 is the <see cref="Menu"/> represented by this <see cref="MenuStructure"/>.</param>
|
||||||
public MenuStructure GetSubStructure(int index) => new MenuStructure(GetSubMenu(index));
|
public MenuStructure GetSubStructure(int index) => new MenuStructure(GetSubMenu(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,248 +1,248 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCasePadding : GridTestCase
|
public class TestCasePadding : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCasePadding() : base(2, 2)
|
public TestCasePadding() : base(2, 2)
|
||||||
{
|
{
|
||||||
Cell(0).AddRange(new Drawable[]
|
Cell(0).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = @"Padding - 20 All Sides" },
|
new SpriteText { Text = @"Padding - 20 All Sides" },
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
new PaddedBox(Color4.Blue)
|
new PaddedBox(Color4.Blue)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(20),
|
Padding = new MarginPadding(20),
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new PaddedBox(Color4.DarkSeaGreen)
|
new PaddedBox(Color4.DarkSeaGreen)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(40),
|
Padding = new MarginPadding(40),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre
|
Anchor = Anchor.Centre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(1).AddRange(new Drawable[]
|
Cell(1).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = @"Padding - 20 Top, Left" },
|
new SpriteText { Text = @"Padding - 20 Top, Left" },
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
new PaddedBox(Color4.Blue)
|
new PaddedBox(Color4.Blue)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 20,
|
Top = 20,
|
||||||
Left = 20,
|
Left = 20,
|
||||||
},
|
},
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new PaddedBox(Color4.DarkSeaGreen)
|
new PaddedBox(Color4.DarkSeaGreen)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(40),
|
Padding = new MarginPadding(40),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre
|
Anchor = Anchor.Centre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(2).AddRange(new Drawable[]
|
Cell(2).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = @"Margin - 20 All Sides" },
|
new SpriteText { Text = @"Margin - 20 All Sides" },
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
new PaddedBox(Color4.Blue)
|
new PaddedBox(Color4.Blue)
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(20),
|
Margin = new MarginPadding(20),
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new PaddedBox(Color4.DarkSeaGreen)
|
new PaddedBox(Color4.DarkSeaGreen)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(20),
|
Padding = new MarginPadding(20),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre
|
Anchor = Anchor.Centre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Cell(3).AddRange(new Drawable[]
|
Cell(3).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText { Text = @"Margin - 20 Top, Left" },
|
new SpriteText { Text = @"Margin - 20 Top, Left" },
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
},
|
},
|
||||||
new PaddedBox(Color4.Blue)
|
new PaddedBox(Color4.Blue)
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding
|
Margin = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 20,
|
Top = 20,
|
||||||
Left = 20,
|
Left = 20,
|
||||||
},
|
},
|
||||||
Size = new Vector2(200),
|
Size = new Vector2(200),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new PaddedBox(Color4.DarkSeaGreen)
|
new PaddedBox(Color4.DarkSeaGreen)
|
||||||
{
|
{
|
||||||
Padding = new MarginPadding(40),
|
Padding = new MarginPadding(40),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre
|
Anchor = Anchor.Centre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PaddedBox : Container
|
private class PaddedBox : Container
|
||||||
{
|
{
|
||||||
private readonly SpriteText t1;
|
private readonly SpriteText t1;
|
||||||
private readonly SpriteText t2;
|
private readonly SpriteText t2;
|
||||||
private readonly SpriteText t3;
|
private readonly SpriteText t3;
|
||||||
private readonly SpriteText t4;
|
private readonly SpriteText t4;
|
||||||
|
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
public PaddedBox(Color4 colour)
|
public PaddedBox(Color4 colour)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colour,
|
Colour = colour,
|
||||||
},
|
},
|
||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
t1 = new SpriteText
|
t1 = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
t2 = new SpriteText
|
t2 = new SpriteText
|
||||||
{
|
{
|
||||||
Rotation = 90,
|
Rotation = 90,
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
t3 = new SpriteText
|
t3 = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.BottomCentre
|
Origin = Anchor.BottomCentre
|
||||||
},
|
},
|
||||||
t4 = new SpriteText
|
t4 = new SpriteText
|
||||||
{
|
{
|
||||||
Rotation = -90,
|
Rotation = -90,
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
|
||||||
{
|
{
|
||||||
t1.Text = (Padding.Top > 0 ? $"p{Padding.Top}" : string.Empty) + (Margin.Top > 0 ? $"m{Margin.Top}" : string.Empty);
|
t1.Text = (Padding.Top > 0 ? $"p{Padding.Top}" : string.Empty) + (Margin.Top > 0 ? $"m{Margin.Top}" : string.Empty);
|
||||||
t2.Text = (Padding.Right > 0 ? $"p{Padding.Right}" : string.Empty) + (Margin.Right > 0 ? $"m{Margin.Right}" : string.Empty);
|
t2.Text = (Padding.Right > 0 ? $"p{Padding.Right}" : string.Empty) + (Margin.Right > 0 ? $"m{Margin.Right}" : string.Empty);
|
||||||
t3.Text = (Padding.Bottom > 0 ? $"p{Padding.Bottom}" : string.Empty) + (Margin.Bottom > 0 ? $"m{Margin.Bottom}" : string.Empty);
|
t3.Text = (Padding.Bottom > 0 ? $"p{Padding.Bottom}" : string.Empty) + (Margin.Bottom > 0 ? $"m{Margin.Bottom}" : string.Empty);
|
||||||
t4.Text = (Padding.Left > 0 ? $"p{Padding.Left}" : string.Empty) + (Margin.Left > 0 ? $"m{Margin.Left}" : string.Empty);
|
t4.Text = (Padding.Left > 0 ? $"p{Padding.Left}" : string.Empty) + (Margin.Left > 0 ? $"m{Margin.Left}" : string.Empty);
|
||||||
|
|
||||||
return base.Invalidate(invalidation, source, shallPropagate);
|
return base.Invalidate(invalidation, source, shallPropagate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
Position += state.Mouse.Delta;
|
Position += state.Mouse.Delta;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragEnd(InputState state) => true;
|
protected override bool OnDragEnd(InputState state) => true;
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state) => true;
|
protected override bool OnDragStart(InputState state) => true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +1,168 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Lines;
|
using osu.Framework.Graphics.Lines;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCasePathInput : TestCase
|
public class TestCasePathInput : TestCase
|
||||||
{
|
{
|
||||||
private const float path_width = 50;
|
private const float path_width = 50;
|
||||||
private const float path_radius = path_width / 2;
|
private const float path_radius = path_width / 2;
|
||||||
|
|
||||||
private readonly Path path;
|
private readonly Path path;
|
||||||
private readonly TestPoint testPoint;
|
private readonly TestPoint testPoint;
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
|
|
||||||
public TestCasePathInput()
|
public TestCasePathInput()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
path = new HoverablePath(),
|
path = new HoverablePath(),
|
||||||
testPoint = new TestPoint(),
|
testPoint = new TestPoint(),
|
||||||
text = new SpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre }
|
text = new SpriteText { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre }
|
||||||
};
|
};
|
||||||
|
|
||||||
testHorizontalPath();
|
testHorizontalPath();
|
||||||
testDiagonalPath();
|
testDiagonalPath();
|
||||||
testVShaped();
|
testVShaped();
|
||||||
testOverlapping();
|
testOverlapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testHorizontalPath()
|
private void testHorizontalPath()
|
||||||
{
|
{
|
||||||
addPath("Horizontal path", new Vector2(100), new Vector2(300, 100));
|
addPath("Horizontal path", new Vector2(100), new Vector2(300, 100));
|
||||||
// Left out
|
// Left out
|
||||||
test(new Vector2(40, 100), false);
|
test(new Vector2(40, 100), false);
|
||||||
// Left in
|
// Left in
|
||||||
test(new Vector2(80, 100), true);
|
test(new Vector2(80, 100), true);
|
||||||
// Cap out
|
// Cap out
|
||||||
test(new Vector2(60), false);
|
test(new Vector2(60), false);
|
||||||
// Cap in
|
// Cap in
|
||||||
test(new Vector2(70), true);
|
test(new Vector2(70), true);
|
||||||
//Right out
|
//Right out
|
||||||
test(new Vector2(360, 100), false);
|
test(new Vector2(360, 100), false);
|
||||||
// Centre
|
// Centre
|
||||||
test(new Vector2(200, 100), true);
|
test(new Vector2(200, 100), true);
|
||||||
// Top out
|
// Top out
|
||||||
test(new Vector2(190, 40), false);
|
test(new Vector2(190, 40), false);
|
||||||
// Top in
|
// Top in
|
||||||
test(new Vector2(190, 60), true);
|
test(new Vector2(190, 60), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testDiagonalPath()
|
private void testDiagonalPath()
|
||||||
{
|
{
|
||||||
addPath("Diagonal path", new Vector2(300), new Vector2(100));
|
addPath("Diagonal path", new Vector2(300), new Vector2(100));
|
||||||
// Top-left out
|
// Top-left out
|
||||||
test(new Vector2(50), false);
|
test(new Vector2(50), false);
|
||||||
// Top-left in
|
// Top-left in
|
||||||
test(new Vector2(80), true);
|
test(new Vector2(80), true);
|
||||||
// Left out
|
// Left out
|
||||||
test(new Vector2(145, 235), false);
|
test(new Vector2(145, 235), false);
|
||||||
// Left in
|
// Left in
|
||||||
test(new Vector2(170, 235), true);
|
test(new Vector2(170, 235), true);
|
||||||
// Cap out
|
// Cap out
|
||||||
test(new Vector2(355, 300), false);
|
test(new Vector2(355, 300), false);
|
||||||
// Cap in
|
// Cap in
|
||||||
test(new Vector2(340, 300), true);
|
test(new Vector2(340, 300), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testVShaped()
|
private void testVShaped()
|
||||||
{
|
{
|
||||||
addPath("V-shaped", new Vector2(100), new Vector2(300), new Vector2(500, 100));
|
addPath("V-shaped", new Vector2(100), new Vector2(300), new Vector2(500, 100));
|
||||||
// Intersection out
|
// Intersection out
|
||||||
test(new Vector2(300, 225), false);
|
test(new Vector2(300, 225), false);
|
||||||
// Intersection in
|
// Intersection in
|
||||||
test(new Vector2(300, 240), true);
|
test(new Vector2(300, 240), true);
|
||||||
// Bottom cap out
|
// Bottom cap out
|
||||||
test(new Vector2(300, 355), false);
|
test(new Vector2(300, 355), false);
|
||||||
// Bottom cap in
|
// Bottom cap in
|
||||||
test(new Vector2(300, 340), true);
|
test(new Vector2(300, 340), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testOverlapping()
|
private void testOverlapping()
|
||||||
{
|
{
|
||||||
addPath("Overlapping", new Vector2(100), new Vector2(600), new Vector2(800, 300), new Vector2(100, 400));
|
addPath("Overlapping", new Vector2(100), new Vector2(600), new Vector2(800, 300), new Vector2(100, 400));
|
||||||
// Left intersection out
|
// Left intersection out
|
||||||
test(new Vector2(250, 325), false);
|
test(new Vector2(250, 325), false);
|
||||||
// Left intersection in
|
// Left intersection in
|
||||||
test(new Vector2(260, 325), true);
|
test(new Vector2(260, 325), true);
|
||||||
// Top intersection out
|
// Top intersection out
|
||||||
test(new Vector2(380, 300), false);
|
test(new Vector2(380, 300), false);
|
||||||
// Top intersection in
|
// Top intersection in
|
||||||
test(new Vector2(380, 320), true);
|
test(new Vector2(380, 320), true);
|
||||||
// Triangle left intersection out
|
// Triangle left intersection out
|
||||||
test(new Vector2(475, 400), false);
|
test(new Vector2(475, 400), false);
|
||||||
// Triangle left intersection in
|
// Triangle left intersection in
|
||||||
test(new Vector2(460, 400), true);
|
test(new Vector2(460, 400), true);
|
||||||
// Triangle right intersection out
|
// Triangle right intersection out
|
||||||
test(new Vector2(690, 370), false);
|
test(new Vector2(690, 370), false);
|
||||||
// Triangle right intersection in
|
// Triangle right intersection in
|
||||||
test(new Vector2(700, 370), true);
|
test(new Vector2(700, 370), true);
|
||||||
// Triangle bottom intersection out
|
// Triangle bottom intersection out
|
||||||
test(new Vector2(590, 515), false);
|
test(new Vector2(590, 515), false);
|
||||||
// Triangle bottom intersection in
|
// Triangle bottom intersection in
|
||||||
test(new Vector2(590, 525), true);
|
test(new Vector2(590, 525), true);
|
||||||
// Centre intersection in
|
// Centre intersection in
|
||||||
test(new Vector2(370, 360), true);
|
test(new Vector2(370, 360), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(InputState state)
|
protected override bool OnMouseMove(InputState state)
|
||||||
{
|
{
|
||||||
text.Text = path.ToLocalSpace(state.Mouse.NativeState.Position).ToString();
|
text.Text = path.ToLocalSpace(state.Mouse.NativeState.Position).ToString();
|
||||||
return base.OnMouseMove(state);
|
return base.OnMouseMove(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPath(string name, params Vector2[] vertices) => AddStep(name, () =>
|
private void addPath(string name, params Vector2[] vertices) => AddStep(name, () =>
|
||||||
{
|
{
|
||||||
path.PathWidth = path_width;
|
path.PathWidth = path_width;
|
||||||
path.Positions = vertices.ToList();
|
path.Positions = vertices.ToList();
|
||||||
});
|
});
|
||||||
|
|
||||||
private void test(Vector2 position, bool shouldReceiveMouseInput)
|
private void test(Vector2 position, bool shouldReceiveMouseInput)
|
||||||
{
|
{
|
||||||
AddAssert($"Test @ {position} = {shouldReceiveMouseInput}", () =>
|
AddAssert($"Test @ {position} = {shouldReceiveMouseInput}", () =>
|
||||||
{
|
{
|
||||||
testPoint.Position = position;
|
testPoint.Position = position;
|
||||||
return path.ReceiveMouseInputAt(path.ToScreenSpace(position)) == shouldReceiveMouseInput;
|
return path.ReceiveMouseInputAt(path.ToScreenSpace(position)) == shouldReceiveMouseInput;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestPoint : CircularContainer
|
private class TestPoint : CircularContainer
|
||||||
{
|
{
|
||||||
public TestPoint()
|
public TestPoint()
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
Size = new Vector2(5);
|
Size = new Vector2(5);
|
||||||
Colour = Color4.Red;
|
Colour = Color4.Red;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
|
|
||||||
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
|
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HoverablePath : Path
|
private class HoverablePath : Path
|
||||||
{
|
{
|
||||||
protected override bool OnHover(InputState state)
|
protected override bool OnHover(InputState state)
|
||||||
{
|
{
|
||||||
Colour = Color4.Green;
|
Colour = Color4.Green;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(InputState state)
|
protected override void OnHoverLost(InputState state)
|
||||||
{
|
{
|
||||||
Colour = Color4.White;
|
Colour = Color4.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("ensure validity of drawables when receiving certain values")]
|
[System.ComponentModel.Description("ensure validity of drawables when receiving certain values")]
|
||||||
public class TestCasePropertyBoundaries : TestCase
|
public class TestCasePropertyBoundaries : TestCase
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
testPositiveScale();
|
testPositiveScale();
|
||||||
testZeroScale();
|
testZeroScale();
|
||||||
testNegativeScale();
|
testNegativeScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testPositiveScale()
|
private void testPositiveScale()
|
||||||
{
|
{
|
||||||
var box = new Box
|
var box = new Box
|
||||||
{
|
{
|
||||||
Size = new Vector2(100),
|
Size = new Vector2(100),
|
||||||
Scale = new Vector2(2)
|
Scale = new Vector2(2)
|
||||||
};
|
};
|
||||||
|
|
||||||
Add(box);
|
Add(box);
|
||||||
|
|
||||||
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
||||||
AddAssert("Box is present", () => box.IsPresent);
|
AddAssert("Box is present", () => box.IsPresent);
|
||||||
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testZeroScale()
|
private void testZeroScale()
|
||||||
{
|
{
|
||||||
var box = new Box
|
var box = new Box
|
||||||
{
|
{
|
||||||
Size = new Vector2(100),
|
Size = new Vector2(100),
|
||||||
Scale = new Vector2(0)
|
Scale = new Vector2(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
Add(box);
|
Add(box);
|
||||||
|
|
||||||
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
||||||
AddAssert("Box is present", () => !box.IsPresent);
|
AddAssert("Box is present", () => !box.IsPresent);
|
||||||
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testNegativeScale()
|
private void testNegativeScale()
|
||||||
{
|
{
|
||||||
var box = new Box
|
var box = new Box
|
||||||
{
|
{
|
||||||
Size = new Vector2(100),
|
Size = new Vector2(100),
|
||||||
Scale = new Vector2(-2)
|
Scale = new Vector2(-2)
|
||||||
};
|
};
|
||||||
|
|
||||||
Add(box);
|
Add(box);
|
||||||
|
|
||||||
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
AddAssert("Box is loaded", () => box.LoadState >= LoadState.Ready);
|
||||||
AddAssert("Box is present", () => box.IsPresent);
|
AddAssert("Box is present", () => box.IsPresent);
|
||||||
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
AddAssert("Box has valid draw matrix", () => checkDrawInfo(box.DrawInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool checkDrawInfo(DrawInfo drawInfo)
|
private bool checkDrawInfo(DrawInfo drawInfo)
|
||||||
{
|
{
|
||||||
return checkFloat(drawInfo.Matrix.M11)
|
return checkFloat(drawInfo.Matrix.M11)
|
||||||
&& checkFloat(drawInfo.Matrix.M12)
|
&& checkFloat(drawInfo.Matrix.M12)
|
||||||
&& checkFloat(drawInfo.Matrix.M13)
|
&& checkFloat(drawInfo.Matrix.M13)
|
||||||
&& checkFloat(drawInfo.Matrix.M21)
|
&& checkFloat(drawInfo.Matrix.M21)
|
||||||
&& checkFloat(drawInfo.Matrix.M22)
|
&& checkFloat(drawInfo.Matrix.M22)
|
||||||
&& checkFloat(drawInfo.Matrix.M23)
|
&& checkFloat(drawInfo.Matrix.M23)
|
||||||
&& checkFloat(drawInfo.Matrix.M31)
|
&& checkFloat(drawInfo.Matrix.M31)
|
||||||
&& checkFloat(drawInfo.Matrix.M32)
|
&& checkFloat(drawInfo.Matrix.M32)
|
||||||
&& checkFloat(drawInfo.Matrix.M33)
|
&& checkFloat(drawInfo.Matrix.M33)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M11)
|
&& checkFloat(drawInfo.MatrixInverse.M11)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M12)
|
&& checkFloat(drawInfo.MatrixInverse.M12)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M13)
|
&& checkFloat(drawInfo.MatrixInverse.M13)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M21)
|
&& checkFloat(drawInfo.MatrixInverse.M21)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M22)
|
&& checkFloat(drawInfo.MatrixInverse.M22)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M23)
|
&& checkFloat(drawInfo.MatrixInverse.M23)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M31)
|
&& checkFloat(drawInfo.MatrixInverse.M31)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M32)
|
&& checkFloat(drawInfo.MatrixInverse.M32)
|
||||||
&& checkFloat(drawInfo.MatrixInverse.M33);
|
&& checkFloat(drawInfo.MatrixInverse.M33);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool checkFloat(float value) => !float.IsNaN(value) && !float.IsInfinity(value) && !float.IsNegativeInfinity(value);
|
private bool checkFloat(float value) => !float.IsNaN(value) && !float.IsInfinity(value) && !float.IsNegativeInfinity(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,178 +1,178 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Physics;
|
using osu.Framework.Physics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseRigidBody : TestCase
|
public class TestCaseRigidBody : TestCase
|
||||||
{
|
{
|
||||||
private readonly TestRigidBodySimulation sim;
|
private readonly TestRigidBodySimulation sim;
|
||||||
|
|
||||||
private float restitutionBacking;
|
private float restitutionBacking;
|
||||||
private float restitution
|
private float restitution
|
||||||
{
|
{
|
||||||
get { return restitutionBacking; }
|
get { return restitutionBacking; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
restitutionBacking = value;
|
restitutionBacking = value;
|
||||||
|
|
||||||
if (sim == null)
|
if (sim == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var d in sim.Children)
|
foreach (var d in sim.Children)
|
||||||
d.Restitution = value;
|
d.Restitution = value;
|
||||||
sim.Restitution = value;
|
sim.Restitution = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float frictionBacking;
|
private float frictionBacking;
|
||||||
private float friction
|
private float friction
|
||||||
{
|
{
|
||||||
get { return frictionBacking; }
|
get { return frictionBacking; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
frictionBacking = value;
|
frictionBacking = value;
|
||||||
|
|
||||||
if (sim == null)
|
if (sim == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var d in sim.Children)
|
foreach (var d in sim.Children)
|
||||||
d.FrictionCoefficient = value;
|
d.FrictionCoefficient = value;
|
||||||
sim.FrictionCoefficient = value;
|
sim.FrictionCoefficient = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseRigidBody()
|
public TestCaseRigidBody()
|
||||||
{
|
{
|
||||||
Child = sim = new TestRigidBodySimulation { RelativeSizeAxes = Axes.Both };
|
Child = sim = new TestRigidBodySimulation { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
AddStep("Reset bodies", reset);
|
AddStep("Reset bodies", reset);
|
||||||
|
|
||||||
AddSliderStep("Simulation speed", 0f, 1f, 0.5f, v => sim.SimulationSpeed = v);
|
AddSliderStep("Simulation speed", 0f, 1f, 0.5f, v => sim.SimulationSpeed = v);
|
||||||
AddSliderStep("Restitution", -1f, 1f, 1f, v => restitution = v);
|
AddSliderStep("Restitution", -1f, 1f, 1f, v => restitution = v);
|
||||||
AddSliderStep("Friction", -1f, 5f, 0f, v => friction = v);
|
AddSliderStep("Friction", -1f, 5f, 0f, v => friction = v);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool overlapsAny(Drawable d)
|
private bool overlapsAny(Drawable d)
|
||||||
{
|
{
|
||||||
foreach (var other in sim.Children)
|
foreach (var other in sim.Children)
|
||||||
if (other.ScreenSpaceDrawQuad.AABB.IntersectsWith(d.ScreenSpaceDrawQuad.AABB))
|
if (other.ScreenSpaceDrawQuad.AABB.IntersectsWith(d.ScreenSpaceDrawQuad.AABB))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateN(int n, Func<RigidBodyContainer<Drawable>> generate)
|
private void generateN(int n, Func<RigidBodyContainer<Drawable>> generate)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
RigidBodyContainer<Drawable> d;
|
RigidBodyContainer<Drawable> d;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
d = generate();
|
d = generate();
|
||||||
}
|
}
|
||||||
while (overlapsAny(d));
|
while (overlapsAny(d));
|
||||||
|
|
||||||
sim.Add(d);
|
sim.Add(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset()
|
private void reset()
|
||||||
{
|
{
|
||||||
sim.Clear();
|
sim.Clear();
|
||||||
|
|
||||||
Random random = new Random(1337);
|
Random random = new Random(1337);
|
||||||
|
|
||||||
// Add a textbox... because we can.
|
// Add a textbox... because we can.
|
||||||
generateN(3, () => new RigidBodyContainer<Drawable>
|
generateN(3, () => new RigidBodyContainer<Drawable>
|
||||||
{
|
{
|
||||||
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
||||||
Size = new Vector2(1, 0.1f + 0.2f * (float)random.NextDouble()) * (150 + 150 * (float)random.NextDouble()),
|
Size = new Vector2(1, 0.1f + 0.2f * (float)random.NextDouble()) * (150 + 150 * (float)random.NextDouble()),
|
||||||
Rotation = (float)random.NextDouble() * 360,
|
Rotation = (float)random.NextDouble() * 360,
|
||||||
Child = new TextBox
|
Child = new TextBox
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
PlaceholderText = "Text box fun!",
|
PlaceholderText = "Text box fun!",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Boxes
|
// Boxes
|
||||||
generateN(10, () => new TestRigidBody
|
generateN(10, () => new TestRigidBody
|
||||||
{
|
{
|
||||||
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
||||||
Size = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 200,
|
Size = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 200,
|
||||||
Rotation = (float)random.NextDouble() * 360,
|
Rotation = (float)random.NextDouble() * 360,
|
||||||
Colour = new Color4(253, 253, 253, 255),
|
Colour = new Color4(253, 253, 253, 255),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Circles
|
// Circles
|
||||||
generateN(5, () =>
|
generateN(5, () =>
|
||||||
{
|
{
|
||||||
Vector2 size = new Vector2((float)random.NextDouble()) * 200;
|
Vector2 size = new Vector2((float)random.NextDouble()) * 200;
|
||||||
return new TestRigidBody
|
return new TestRigidBody
|
||||||
{
|
{
|
||||||
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
||||||
Size = size,
|
Size = size,
|
||||||
Rotation = (float)random.NextDouble() * 360,
|
Rotation = (float)random.NextDouble() * 360,
|
||||||
CornerRadius = size.X / 2,
|
CornerRadius = size.X / 2,
|
||||||
Colour = new Color4(253, 253, 253, 255),
|
Colour = new Color4(253, 253, 253, 255),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Totally random stuff
|
// Totally random stuff
|
||||||
generateN(10, () =>
|
generateN(10, () =>
|
||||||
{
|
{
|
||||||
Vector2 size = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 200;
|
Vector2 size = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 200;
|
||||||
return new TestRigidBody
|
return new TestRigidBody
|
||||||
{
|
{
|
||||||
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
Position = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 1000,
|
||||||
Size = size,
|
Size = size,
|
||||||
Rotation = (float)random.NextDouble() * 360,
|
Rotation = (float)random.NextDouble() * 360,
|
||||||
Shear = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 2 - new Vector2(1),
|
Shear = new Vector2((float)random.NextDouble(), (float)random.NextDouble()) * 2 - new Vector2(1),
|
||||||
CornerRadius = (float)random.NextDouble() * Math.Min(size.X, size.Y) / 2,
|
CornerRadius = (float)random.NextDouble() * Math.Min(size.X, size.Y) / 2,
|
||||||
Colour = new Color4(253, 253, 253, 255),
|
Colour = new Color4(253, 253, 253, 255),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set appropriate properties
|
// Set appropriate properties
|
||||||
foreach (var d in sim.Children)
|
foreach (var d in sim.Children)
|
||||||
{
|
{
|
||||||
d.Mass = Math.Max(0.01f, d.ScreenSpaceDrawQuad.Area);
|
d.Mass = Math.Max(0.01f, d.ScreenSpaceDrawQuad.Area);
|
||||||
d.FrictionCoefficient = friction;
|
d.FrictionCoefficient = friction;
|
||||||
d.Restitution = restitution;
|
d.Restitution = restitution;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRigidBody : RigidBodyContainer<Drawable>
|
private class TestRigidBody : RigidBodyContainer<Drawable>
|
||||||
{
|
{
|
||||||
public TestRigidBody()
|
public TestRigidBody()
|
||||||
{
|
{
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both };
|
Child = new Box { RelativeSizeAxes = Axes.Both };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestRigidBodySimulation : RigidBodySimulation
|
private class TestRigidBodySimulation : RigidBodySimulation
|
||||||
{
|
{
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
foreach (var d in Children)
|
foreach (var d in Children)
|
||||||
d.ApplyImpulse(new Vector2(RNG.NextSingle() - 0.5f, RNG.NextSingle() - 0.5f) * 100, d.Centre + new Vector2(RNG.NextSingle() - 0.5f, RNG.NextSingle() - 0.5f) * 100);
|
d.ApplyImpulse(new Vector2(RNG.NextSingle() - 0.5f, RNG.NextSingle() - 0.5f) * 100, d.Centre + new Vector2(RNG.NextSingle() - 0.5f, RNG.NextSingle() - 0.5f) * 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,117 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseScreen : TestCase
|
public class TestCaseScreen : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseScreen()
|
public TestCaseScreen()
|
||||||
{
|
{
|
||||||
Add(new TestScreen());
|
Add(new TestScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestScreen : Screen
|
private class TestScreen : Screen
|
||||||
{
|
{
|
||||||
public int Sequence;
|
public int Sequence;
|
||||||
private Button popButton;
|
private Button popButton;
|
||||||
|
|
||||||
private const int transition_time = 500;
|
private const int transition_time = 500;
|
||||||
|
|
||||||
protected override void OnEntering(Screen last)
|
protected override void OnEntering(Screen last)
|
||||||
{
|
{
|
||||||
if (last != null)
|
if (last != null)
|
||||||
{
|
{
|
||||||
//only show the pop button if we are entered form another screen.
|
//only show the pop button if we are entered form another screen.
|
||||||
popButton.Alpha = 1;
|
popButton.Alpha = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Content.MoveTo(new Vector2(0, -DrawSize.Y));
|
Content.MoveTo(new Vector2(0, -DrawSize.Y));
|
||||||
Content.MoveTo(Vector2.Zero, transition_time, Easing.OutQuint);
|
Content.MoveTo(Vector2.Zero, transition_time, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnExiting(Screen next)
|
protected override bool OnExiting(Screen next)
|
||||||
{
|
{
|
||||||
Content.MoveTo(new Vector2(0, -DrawSize.Y), transition_time, Easing.OutQuint);
|
Content.MoveTo(new Vector2(0, -DrawSize.Y), transition_time, Easing.OutQuint);
|
||||||
return base.OnExiting(next);
|
return base.OnExiting(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnSuspending(Screen next)
|
protected override void OnSuspending(Screen next)
|
||||||
{
|
{
|
||||||
Content.MoveTo(new Vector2(0, DrawSize.Y), transition_time, Easing.OutQuint);
|
Content.MoveTo(new Vector2(0, DrawSize.Y), transition_time, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResuming(Screen last)
|
protected override void OnResuming(Screen last)
|
||||||
{
|
{
|
||||||
Content.MoveTo(Vector2.Zero, transition_time, Easing.OutQuint);
|
Content.MoveTo(Vector2.Zero, transition_time, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(1),
|
Size = new Vector2(1),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Colour = new Color4(
|
Colour = new Color4(
|
||||||
Math.Max(0.5f, RNG.NextSingle()),
|
Math.Max(0.5f, RNG.NextSingle()),
|
||||||
Math.Max(0.5f, RNG.NextSingle()),
|
Math.Max(0.5f, RNG.NextSingle()),
|
||||||
Math.Max(0.5f, RNG.NextSingle()),
|
Math.Max(0.5f, RNG.NextSingle()),
|
||||||
1),
|
1),
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = $@"Mode {Sequence}",
|
Text = $@"Mode {Sequence}",
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
TextSize = 50,
|
TextSize = 50,
|
||||||
},
|
},
|
||||||
popButton = new Button
|
popButton = new Button
|
||||||
{
|
{
|
||||||
Text = @"Pop",
|
Text = @"Pop",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.1f),
|
Size = new Vector2(0.1f),
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
BackgroundColour = Color4.Red,
|
BackgroundColour = Color4.Red,
|
||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
Action = Exit
|
Action = Exit
|
||||||
},
|
},
|
||||||
new Button
|
new Button
|
||||||
{
|
{
|
||||||
Text = @"Push",
|
Text = @"Push",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.1f),
|
Size = new Vector2(0.1f),
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
BackgroundColour = Color4.YellowGreen,
|
BackgroundColour = Color4.YellowGreen,
|
||||||
Action = delegate
|
Action = delegate
|
||||||
{
|
{
|
||||||
Push(new TestScreen
|
Push(new TestScreen
|
||||||
{
|
{
|
||||||
Sequence = Sequence + 1,
|
Sequence = Sequence + 1,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,131 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseScrollableFlow : TestCase
|
public class TestCaseScrollableFlow : TestCase
|
||||||
{
|
{
|
||||||
private readonly ScheduledDelegate boxCreator;
|
private readonly ScheduledDelegate boxCreator;
|
||||||
|
|
||||||
private ScrollContainer scroll;
|
private ScrollContainer scroll;
|
||||||
private FillFlowContainer flow;
|
private FillFlowContainer flow;
|
||||||
|
|
||||||
private void createArea(Direction dir)
|
private void createArea(Direction dir)
|
||||||
{
|
{
|
||||||
Axes scrollAxis = dir == Direction.Horizontal ? Axes.X : Axes.Y;
|
Axes scrollAxis = dir == Direction.Horizontal ? Axes.X : Axes.Y;
|
||||||
|
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
scroll = new ScrollContainer(dir)
|
scroll = new ScrollContainer(dir)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainer
|
flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
LayoutDuration = 100,
|
LayoutDuration = 100,
|
||||||
LayoutEasing = Easing.Out,
|
LayoutEasing = Easing.Out,
|
||||||
Spacing = new Vector2(1, 1),
|
Spacing = new Vector2(1, 1),
|
||||||
RelativeSizeAxes = Axes.Both & ~scrollAxis,
|
RelativeSizeAxes = Axes.Both & ~scrollAxis,
|
||||||
AutoSizeAxes = scrollAxis,
|
AutoSizeAxes = scrollAxis,
|
||||||
Padding = new MarginPadding(5)
|
Padding = new MarginPadding(5)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createAreaBoth()
|
private void createAreaBoth()
|
||||||
{
|
{
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new ScrollContainer(Direction.Horizontal)
|
new ScrollContainer(Direction.Horizontal)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Left = 150 },
|
Padding = new MarginPadding { Left = 150 },
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
scroll = new ScrollContainer
|
scroll = new ScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.X,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainer
|
flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
LayoutDuration = 100,
|
LayoutDuration = 100,
|
||||||
LayoutEasing = Easing.Out,
|
LayoutEasing = Easing.Out,
|
||||||
Spacing = new Vector2(1, 1),
|
Spacing = new Vector2(1, 1),
|
||||||
Size = new Vector2(1000, 0),
|
Size = new Vector2(1000, 0),
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Padding = new MarginPadding(5)
|
Padding = new MarginPadding(5)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
scroll.ScrollContent.AutoSizeAxes = Axes.None;
|
scroll.ScrollContent.AutoSizeAxes = Axes.None;
|
||||||
scroll.ScrollContent.RelativeSizeAxes = Axes.None;
|
scroll.ScrollContent.RelativeSizeAxes = Axes.None;
|
||||||
scroll.ScrollContent.AutoSizeAxes = Axes.Both;
|
scroll.ScrollContent.AutoSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestCaseScrollableFlow()
|
public TestCaseScrollableFlow()
|
||||||
{
|
{
|
||||||
Direction scrollDir;
|
Direction scrollDir;
|
||||||
|
|
||||||
createArea(scrollDir = Direction.Vertical);
|
createArea(scrollDir = Direction.Vertical);
|
||||||
|
|
||||||
AddStep("Vertical", delegate { createArea(scrollDir = Direction.Vertical); });
|
AddStep("Vertical", delegate { createArea(scrollDir = Direction.Vertical); });
|
||||||
AddStep("Horizontal", delegate { createArea(scrollDir = Direction.Horizontal); });
|
AddStep("Horizontal", delegate { createArea(scrollDir = Direction.Horizontal); });
|
||||||
AddStep("Both", createAreaBoth);
|
AddStep("Both", createAreaBoth);
|
||||||
|
|
||||||
AddStep("Dragger Anchor 1", delegate { scroll.ScrollbarAnchor = scrollDir == Direction.Vertical ? Anchor.TopRight : Anchor.BottomLeft; });
|
AddStep("Dragger Anchor 1", delegate { scroll.ScrollbarAnchor = scrollDir == Direction.Vertical ? Anchor.TopRight : Anchor.BottomLeft; });
|
||||||
AddStep("Dragger Anchor 2", delegate { scroll.ScrollbarAnchor = Anchor.TopLeft; });
|
AddStep("Dragger Anchor 2", delegate { scroll.ScrollbarAnchor = Anchor.TopLeft; });
|
||||||
|
|
||||||
AddStep("Dragger Visible", delegate { scroll.ScrollbarVisible = !scroll.ScrollbarVisible; });
|
AddStep("Dragger Visible", delegate { scroll.ScrollbarVisible = !scroll.ScrollbarVisible; });
|
||||||
AddStep("Dragger Overlap", delegate { scroll.ScrollbarOverlapsContent = !scroll.ScrollbarOverlapsContent; });
|
AddStep("Dragger Overlap", delegate { scroll.ScrollbarOverlapsContent = !scroll.ScrollbarOverlapsContent; });
|
||||||
|
|
||||||
boxCreator?.Cancel();
|
boxCreator?.Cancel();
|
||||||
boxCreator = Scheduler.AddDelayed(delegate
|
boxCreator = Scheduler.AddDelayed(delegate
|
||||||
{
|
{
|
||||||
if (Parent == null) return;
|
if (Parent == null) return;
|
||||||
|
|
||||||
Box box;
|
Box box;
|
||||||
Container container = new Container
|
Container container = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(80, 80),
|
Size = new Vector2(80, 80),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
box = new Box
|
box = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1)
|
Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
flow.Add(container);
|
flow.Add(container);
|
||||||
|
|
||||||
container.FadeInFromZero(1000);
|
container.FadeInFromZero(1000);
|
||||||
|
|
||||||
double displayTime = RNG.Next(0, 20000);
|
double displayTime = RNG.Next(0, 20000);
|
||||||
box.Delay(displayTime).ScaleTo(0.5f, 4000).RotateTo((RNG.NextSingle() - 0.5f) * 90, 4000);
|
box.Delay(displayTime).ScaleTo(0.5f, 4000).RotateTo((RNG.NextSingle() - 0.5f) * 90, 4000);
|
||||||
container.Delay(displayTime).FadeOut(4000).Expire();
|
container.Delay(displayTime).FadeOut(4000).Expire();
|
||||||
|
|
||||||
}, 100, true);
|
}, 100, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,191 +1,191 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseSearchContainer : TestCase
|
public class TestCaseSearchContainer : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseSearchContainer()
|
public TestCaseSearchContainer()
|
||||||
{
|
{
|
||||||
SearchContainer<HeaderContainer> search;
|
SearchContainer<HeaderContainer> search;
|
||||||
TextBox textBox;
|
TextBox textBox;
|
||||||
|
|
||||||
Children = new Drawable[] {
|
Children = new Drawable[] {
|
||||||
textBox = new TextBox
|
textBox = new TextBox
|
||||||
{
|
{
|
||||||
Size = new Vector2(300, 40),
|
Size = new Vector2(300, 40),
|
||||||
},
|
},
|
||||||
search = new SearchContainer<HeaderContainer>
|
search = new SearchContainer<HeaderContainer>
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Margin = new MarginPadding { Top = 40 },
|
Margin = new MarginPadding { Top = 40 },
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new HeaderContainer
|
new HeaderContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new HeaderContainer("Subsection 1")
|
new HeaderContainer("Subsection 1")
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "test",
|
Text = "test",
|
||||||
},
|
},
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "TEST",
|
Text = "TEST",
|
||||||
},
|
},
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "123",
|
Text = "123",
|
||||||
},
|
},
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "444",
|
Text = "444",
|
||||||
},
|
},
|
||||||
new FilterableFlowContainer
|
new FilterableFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new []
|
Children = new []
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "multi",
|
Text = "multi",
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "piece",
|
Text = "piece",
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = "container",
|
Text = "container",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "öüäéèêáàâ",
|
Text = "öüäéèêáàâ",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new HeaderContainer("Subsection 2")
|
new HeaderContainer("Subsection 2")
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "?!()[]{}"
|
Text = "?!()[]{}"
|
||||||
},
|
},
|
||||||
new SearchableText
|
new SearchableText
|
||||||
{
|
{
|
||||||
Text = "@€$"
|
Text = "@€$"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
new Dictionary<string, int>
|
new Dictionary<string, int>
|
||||||
{
|
{
|
||||||
{ "test", 2 },
|
{ "test", 2 },
|
||||||
{ "sUbSeCtIoN 1", 6 },
|
{ "sUbSeCtIoN 1", 6 },
|
||||||
{ "€", 1 },
|
{ "€", 1 },
|
||||||
{ "èê", 1 },
|
{ "èê", 1 },
|
||||||
{ "321", 0 },
|
{ "321", 0 },
|
||||||
{ "mul pi", 1},
|
{ "mul pi", 1},
|
||||||
{ "header", 8 }
|
{ "header", 8 }
|
||||||
}.ToList().ForEach(term =>
|
}.ToList().ForEach(term =>
|
||||||
{
|
{
|
||||||
AddStep("Search term: " + term.Key, () => search.SearchTerm = term.Key);
|
AddStep("Search term: " + term.Key, () => search.SearchTerm = term.Key);
|
||||||
AddAssert("Visible end-children: " + term.Value, () => term.Value == search.Children.SelectMany(container => container.Children.Cast<Container>()).SelectMany(container => container.Children).Count(drawable => drawable.IsPresent));
|
AddAssert("Visible end-children: " + term.Value, () => term.Value == search.Children.SelectMany(container => container.Children.Cast<Container>()).SelectMany(container => container.Children).Count(drawable => drawable.IsPresent));
|
||||||
});
|
});
|
||||||
|
|
||||||
textBox.Current.ValueChanged += newValue => search.SearchTerm = newValue;
|
textBox.Current.ValueChanged += newValue => search.SearchTerm = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HeaderContainer : Container, IHasFilterableChildren
|
private class HeaderContainer : Container, IHasFilterableChildren
|
||||||
{
|
{
|
||||||
public IEnumerable<string> FilterTerms => header.FilterTerms;
|
public IEnumerable<string> FilterTerms => header.FilterTerms;
|
||||||
|
|
||||||
public bool MatchingFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
this.FadeIn();
|
this.FadeIn();
|
||||||
else
|
else
|
||||||
this.FadeOut();
|
this.FadeOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
||||||
|
|
||||||
protected override Container<Drawable> Content => flowContainer;
|
protected override Container<Drawable> Content => flowContainer;
|
||||||
|
|
||||||
private readonly SearchableText header;
|
private readonly SearchableText header;
|
||||||
private readonly FillFlowContainer flowContainer;
|
private readonly FillFlowContainer flowContainer;
|
||||||
|
|
||||||
public HeaderContainer(string headerText = "Header")
|
public HeaderContainer(string headerText = "Header")
|
||||||
{
|
{
|
||||||
AddInternal(header = new SearchableText
|
AddInternal(header = new SearchableText
|
||||||
{
|
{
|
||||||
Text = headerText,
|
Text = headerText,
|
||||||
});
|
});
|
||||||
AddInternal(flowContainer = new FillFlowContainer
|
AddInternal(flowContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding { Top = header.TextSize, Left = 30 },
|
Margin = new MarginPadding { Top = header.TextSize, Left = 30 },
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FilterableFlowContainer : FillFlowContainer, IFilterable
|
private class FilterableFlowContainer : FillFlowContainer, IFilterable
|
||||||
{
|
{
|
||||||
public IEnumerable<string> FilterTerms => Children.OfType<IHasFilterTerms>().SelectMany(d => d.FilterTerms);
|
public IEnumerable<string> FilterTerms => Children.OfType<IHasFilterTerms>().SelectMany(d => d.FilterTerms);
|
||||||
|
|
||||||
public bool MatchingFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
Show();
|
Show();
|
||||||
else
|
else
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SearchableText : SpriteText, IFilterable
|
private class SearchableText : SpriteText, IFilterable
|
||||||
{
|
{
|
||||||
public bool MatchingFilter
|
public bool MatchingFilter
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
Show();
|
Show();
|
||||||
else
|
else
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,68 +1,68 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseSliderbar : TestCase
|
public class TestCaseSliderbar : TestCase
|
||||||
{
|
{
|
||||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
||||||
private readonly BindableDouble sliderBarValue; //keep a reference to avoid GC of the bindable
|
private readonly BindableDouble sliderBarValue; //keep a reference to avoid GC of the bindable
|
||||||
private readonly SpriteText sliderbarText;
|
private readonly SpriteText sliderbarText;
|
||||||
|
|
||||||
public TestCaseSliderbar()
|
public TestCaseSliderbar()
|
||||||
{
|
{
|
||||||
sliderBarValue = new BindableDouble(8)
|
sliderBarValue = new BindableDouble(8)
|
||||||
{
|
{
|
||||||
MinValue = -10,
|
MinValue = -10,
|
||||||
MaxValue = 10
|
MaxValue = 10
|
||||||
};
|
};
|
||||||
sliderBarValue.ValueChanged += sliderBarValueChanged;
|
sliderBarValue.ValueChanged += sliderBarValueChanged;
|
||||||
|
|
||||||
sliderbarText = new SpriteText
|
sliderbarText = new SpriteText
|
||||||
{
|
{
|
||||||
Text = $"Selected value: {sliderBarValue.Value}",
|
Text = $"Selected value: {sliderBarValue.Value}",
|
||||||
Position = new Vector2(25, 0)
|
Position = new Vector2(25, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
SliderBar<double> sliderBar = new BasicSliderBar<double>
|
SliderBar<double> sliderBar = new BasicSliderBar<double>
|
||||||
{
|
{
|
||||||
Size = new Vector2(200, 10),
|
Size = new Vector2(200, 10),
|
||||||
Position = new Vector2(25, 25),
|
Position = new Vector2(25, 25),
|
||||||
Color = Color4.White,
|
Color = Color4.White,
|
||||||
SelectionColor = Color4.Pink,
|
SelectionColor = Color4.Pink,
|
||||||
KeyboardStep = 1
|
KeyboardStep = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
sliderBar.Current.BindTo(sliderBarValue);
|
sliderBar.Current.BindTo(sliderBarValue);
|
||||||
|
|
||||||
Add(sliderBar);
|
Add(sliderBar);
|
||||||
Add(sliderbarText);
|
Add(sliderbarText);
|
||||||
|
|
||||||
Add(sliderBar = new BasicSliderBar<double>
|
Add(sliderBar = new BasicSliderBar<double>
|
||||||
{
|
{
|
||||||
Size = new Vector2(200, 10),
|
Size = new Vector2(200, 10),
|
||||||
RangePadding = 20,
|
RangePadding = 20,
|
||||||
Position = new Vector2(25, 45),
|
Position = new Vector2(25, 45),
|
||||||
Color = Color4.White,
|
Color = Color4.White,
|
||||||
SelectionColor = Color4.Pink,
|
SelectionColor = Color4.Pink,
|
||||||
KeyboardStep = 1,
|
KeyboardStep = 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
sliderBar.Current.BindTo(sliderBarValue);
|
sliderBar.Current.BindTo(sliderBarValue);
|
||||||
|
|
||||||
AddSliderStep("Value", -10.0, 10.0, 0.0, v => sliderBarValue.Value = v);
|
AddSliderStep("Value", -10.0, 10.0, 0.0, v => sliderBarValue.Value = v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sliderBarValueChanged(double newValue)
|
private void sliderBarValueChanged(double newValue)
|
||||||
{
|
{
|
||||||
sliderbarText.Text = $"Selected value: {newValue:N}";
|
sliderbarText.Text = $"Selected value: {newValue:N}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseSmoothedEdges : GridTestCase
|
public class TestCaseSmoothedEdges : GridTestCase
|
||||||
{
|
{
|
||||||
public TestCaseSmoothedEdges() : base(2, 2)
|
public TestCaseSmoothedEdges() : base(2, 2)
|
||||||
{
|
{
|
||||||
Vector2[] smoothnesses =
|
Vector2[] smoothnesses =
|
||||||
{
|
{
|
||||||
new Vector2(0, 0),
|
new Vector2(0, 0),
|
||||||
new Vector2(0, 2),
|
new Vector2(0, 2),
|
||||||
new Vector2(1, 1),
|
new Vector2(1, 1),
|
||||||
new Vector2(2, 2),
|
new Vector2(2, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < Rows * Cols; ++i)
|
for (int i = 0; i < Rows * Cols; ++i)
|
||||||
{
|
{
|
||||||
Cell(i).AddRange(new Drawable[]
|
Cell(i).AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = $"{nameof(Sprite.EdgeSmoothness)}={smoothnesses[i]}",
|
Text = $"{nameof(Sprite.EdgeSmoothness)}={smoothnesses[i]}",
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
},
|
},
|
||||||
boxes[i] = new Box
|
boxes[i] = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.White,
|
Colour = Color4.White,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
EdgeSmoothness = smoothnesses[i],
|
EdgeSmoothness = smoothnesses[i],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Box[] boxes = new Box[4];
|
private readonly Box[] boxes = new Box[4];
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
foreach (Box box in boxes)
|
foreach (Box box in boxes)
|
||||||
box.Rotation += 0.01f;
|
box.Rotation += 0.01f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,63 +1,63 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseSpriteText : TestCase
|
public class TestCaseSpriteText : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseSpriteText()
|
public TestCaseSpriteText()
|
||||||
{
|
{
|
||||||
FillFlowContainer flow;
|
FillFlowContainer flow;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new ScrollContainer
|
new ScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainer
|
flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
flow.Add(new SpriteText
|
flow.Add(new SpriteText
|
||||||
{
|
{
|
||||||
Text = @"the quick red fox jumps over the lazy brown dog"
|
Text = @"the quick red fox jumps over the lazy brown dog"
|
||||||
});
|
});
|
||||||
flow.Add(new SpriteText
|
flow.Add(new SpriteText
|
||||||
{
|
{
|
||||||
Text = @"THE QUICK RED FOX JUMPS OVER THE LAZY BROWN DOG"
|
Text = @"THE QUICK RED FOX JUMPS OVER THE LAZY BROWN DOG"
|
||||||
});
|
});
|
||||||
flow.Add(new SpriteText
|
flow.Add(new SpriteText
|
||||||
{
|
{
|
||||||
Text = @"0123456789!@#$%^&*()_-+-[]{}.,<>;'\"
|
Text = @"0123456789!@#$%^&*()_-+-[]{}.,<>;'\"
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 1; i <= 200; i++)
|
for (int i = 1; i <= 200; i++)
|
||||||
{
|
{
|
||||||
SpriteText text = new SpriteText
|
SpriteText text = new SpriteText
|
||||||
{
|
{
|
||||||
Text = $@"Font testy at size {i}",
|
Text = $@"Font testy at size {i}",
|
||||||
AllowMultiline = true,
|
AllowMultiline = true,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
TextSize = i
|
TextSize = i
|
||||||
};
|
};
|
||||||
|
|
||||||
flow.Add(text);
|
flow.Add(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,179 +1,179 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTabControl : TestCase
|
public class TestCaseTabControl : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseTabControl()
|
public TestCaseTabControl()
|
||||||
{
|
{
|
||||||
List<KeyValuePair<string, TestEnum>> items = new List<KeyValuePair<string, TestEnum>>();
|
List<KeyValuePair<string, TestEnum>> items = new List<KeyValuePair<string, TestEnum>>();
|
||||||
foreach (var val in (TestEnum[])Enum.GetValues(typeof(TestEnum)))
|
foreach (var val in (TestEnum[])Enum.GetValues(typeof(TestEnum)))
|
||||||
items.Add(new KeyValuePair<string, TestEnum>(val.GetDescription(), val));
|
items.Add(new KeyValuePair<string, TestEnum>(val.GetDescription(), val));
|
||||||
|
|
||||||
StyledTabControl simpleTabcontrol = new StyledTabControl
|
StyledTabControl simpleTabcontrol = new StyledTabControl
|
||||||
{
|
{
|
||||||
Position = new Vector2(200, 50),
|
Position = new Vector2(200, 50),
|
||||||
Size = new Vector2(200, 30),
|
Size = new Vector2(200, 30),
|
||||||
};
|
};
|
||||||
items.AsEnumerable().ForEach(item => simpleTabcontrol.AddItem(item.Value));
|
items.AsEnumerable().ForEach(item => simpleTabcontrol.AddItem(item.Value));
|
||||||
|
|
||||||
StyledTabControl pinnedAndAutoSort = new StyledTabControl
|
StyledTabControl pinnedAndAutoSort = new StyledTabControl
|
||||||
{
|
{
|
||||||
Position = new Vector2(500, 50),
|
Position = new Vector2(500, 50),
|
||||||
Size = new Vector2(200, 30),
|
Size = new Vector2(200, 30),
|
||||||
AutoSort = true
|
AutoSort = true
|
||||||
};
|
};
|
||||||
items.GetRange(0, 7).AsEnumerable().ForEach(item => pinnedAndAutoSort.AddItem(item.Value));
|
items.GetRange(0, 7).AsEnumerable().ForEach(item => pinnedAndAutoSort.AddItem(item.Value));
|
||||||
pinnedAndAutoSort.PinItem(TestEnum.Test5);
|
pinnedAndAutoSort.PinItem(TestEnum.Test5);
|
||||||
|
|
||||||
Add(simpleTabcontrol);
|
Add(simpleTabcontrol);
|
||||||
Add(pinnedAndAutoSort);
|
Add(pinnedAndAutoSort);
|
||||||
|
|
||||||
var nextTest = new Func<TestEnum>(() => items.AsEnumerable()
|
var nextTest = new Func<TestEnum>(() => items.AsEnumerable()
|
||||||
.Select(item => item.Value)
|
.Select(item => item.Value)
|
||||||
.FirstOrDefault(test => !pinnedAndAutoSort.Items.Contains(test)));
|
.FirstOrDefault(test => !pinnedAndAutoSort.Items.Contains(test)));
|
||||||
|
|
||||||
Stack<TestEnum> pinned = new Stack<TestEnum>();
|
Stack<TestEnum> pinned = new Stack<TestEnum>();
|
||||||
|
|
||||||
AddStep("AddItem", () =>
|
AddStep("AddItem", () =>
|
||||||
{
|
{
|
||||||
var item = nextTest.Invoke();
|
var item = nextTest.Invoke();
|
||||||
if (!pinnedAndAutoSort.Items.Contains(item))
|
if (!pinnedAndAutoSort.Items.Contains(item))
|
||||||
pinnedAndAutoSort.AddItem(item);
|
pinnedAndAutoSort.AddItem(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("RemoveItem", () =>
|
AddStep("RemoveItem", () =>
|
||||||
{
|
{
|
||||||
if (pinnedAndAutoSort.Items.Any())
|
if (pinnedAndAutoSort.Items.Any())
|
||||||
{
|
{
|
||||||
pinnedAndAutoSort.RemoveItem(pinnedAndAutoSort.Items.First());
|
pinnedAndAutoSort.RemoveItem(pinnedAndAutoSort.Items.First());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("PinItem", () =>
|
AddStep("PinItem", () =>
|
||||||
{
|
{
|
||||||
var item = nextTest.Invoke();
|
var item = nextTest.Invoke();
|
||||||
|
|
||||||
if (!pinnedAndAutoSort.Items.Contains(item))
|
if (!pinnedAndAutoSort.Items.Contains(item))
|
||||||
{
|
{
|
||||||
pinned.Push(item);
|
pinned.Push(item);
|
||||||
pinnedAndAutoSort.AddItem(item);
|
pinnedAndAutoSort.AddItem(item);
|
||||||
pinnedAndAutoSort.PinItem(item);
|
pinnedAndAutoSort.PinItem(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep("UnpinItem", () =>
|
AddStep("UnpinItem", () =>
|
||||||
{
|
{
|
||||||
if (pinned.Count > 0) pinnedAndAutoSort.UnpinItem(pinned.Pop());
|
if (pinned.Count > 0) pinnedAndAutoSort.UnpinItem(pinned.Pop());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledTabControl : TabControl<TestEnum>
|
private class StyledTabControl : TabControl<TestEnum>
|
||||||
{
|
{
|
||||||
protected override Dropdown<TestEnum> CreateDropdown() => new StyledDropdown();
|
protected override Dropdown<TestEnum> CreateDropdown() => new StyledDropdown();
|
||||||
|
|
||||||
protected override TabItem<TestEnum> CreateTabItem(TestEnum value) => new StyledTabItem(value);
|
protected override TabItem<TestEnum> CreateTabItem(TestEnum value) => new StyledTabItem(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledTabItem : TabItem<TestEnum>
|
private class StyledTabItem : TabItem<TestEnum>
|
||||||
{
|
{
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
|
|
||||||
public override bool IsRemovable => true;
|
public override bool IsRemovable => true;
|
||||||
|
|
||||||
public StyledTabItem(TestEnum value) : base(value)
|
public StyledTabItem(TestEnum value) : base(value)
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
text = new SpriteText
|
text = new SpriteText
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(2),
|
Margin = new MarginPadding(2),
|
||||||
Text = value.ToString(),
|
Text = value.ToString(),
|
||||||
TextSize = 18
|
TextSize = 18
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnActivated() => text.Colour = Color4.MediumPurple;
|
protected override void OnActivated() => text.Colour = Color4.MediumPurple;
|
||||||
|
|
||||||
protected override void OnDeactivated() => text.Colour = Color4.White;
|
protected override void OnDeactivated() => text.Colour = Color4.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledDropdown : Dropdown<TestEnum>
|
private class StyledDropdown : Dropdown<TestEnum>
|
||||||
{
|
{
|
||||||
protected override DropdownMenu CreateMenu() => new StyledDropdownMenu();
|
protected override DropdownMenu CreateMenu() => new StyledDropdownMenu();
|
||||||
|
|
||||||
protected override DropdownHeader CreateHeader() => new StyledDropdownHeader();
|
protected override DropdownHeader CreateHeader() => new StyledDropdownHeader();
|
||||||
|
|
||||||
public StyledDropdown()
|
public StyledDropdown()
|
||||||
{
|
{
|
||||||
Menu.Anchor = Anchor.TopRight;
|
Menu.Anchor = Anchor.TopRight;
|
||||||
Menu.Origin = Anchor.TopRight;
|
Menu.Origin = Anchor.TopRight;
|
||||||
Header.Anchor = Anchor.TopRight;
|
Header.Anchor = Anchor.TopRight;
|
||||||
Header.Origin = Anchor.TopRight;
|
Header.Origin = Anchor.TopRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledDropdownMenu : DropdownMenu
|
private class StyledDropdownMenu : DropdownMenu
|
||||||
{
|
{
|
||||||
public StyledDropdownMenu()
|
public StyledDropdownMenu()
|
||||||
{
|
{
|
||||||
ScrollbarVisible = false;
|
ScrollbarVisible = false;
|
||||||
CornerRadius = 4;
|
CornerRadius = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StyledDropdownHeader : DropdownHeader
|
private class StyledDropdownHeader : DropdownHeader
|
||||||
{
|
{
|
||||||
protected internal override string Label { get; set; }
|
protected internal override string Label { get; set; }
|
||||||
|
|
||||||
public StyledDropdownHeader()
|
public StyledDropdownHeader()
|
||||||
{
|
{
|
||||||
Background.Hide(); // don't need a background
|
Background.Hide(); // don't need a background
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.None;
|
RelativeSizeAxes = Axes.None;
|
||||||
AutoSizeAxes = Axes.X;
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
Foreground.RelativeSizeAxes = Axes.None;
|
Foreground.RelativeSizeAxes = Axes.None;
|
||||||
Foreground.AutoSizeAxes = Axes.Both;
|
Foreground.AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Foreground.Children = new[]
|
Foreground.Children = new[]
|
||||||
{
|
{
|
||||||
new Box { Width = 20, Height = 20 }
|
new Box { Width = 20, Height = 20 }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum TestEnum
|
private enum TestEnum
|
||||||
{
|
{
|
||||||
Test0,
|
Test0,
|
||||||
Test1,
|
Test1,
|
||||||
Test2,
|
Test2,
|
||||||
Test3,
|
Test3,
|
||||||
Test4,
|
Test4,
|
||||||
Test5,
|
Test5,
|
||||||
Test6,
|
Test6,
|
||||||
Test7,
|
Test7,
|
||||||
Test8,
|
Test8,
|
||||||
Test9,
|
Test9,
|
||||||
Test10,
|
Test10,
|
||||||
Test11,
|
Test11,
|
||||||
Test12
|
Test12
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,143 +1,143 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTextBox : TestCase
|
public class TestCaseTextBox : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseTextBox()
|
public TestCaseTextBox()
|
||||||
{
|
{
|
||||||
FillFlowContainer textBoxes = new FillFlowContainer
|
FillFlowContainer textBoxes = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 50),
|
Spacing = new Vector2(0, 50),
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 50,
|
Top = 50,
|
||||||
},
|
},
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.9f, 1)
|
Size = new Vector2(0.9f, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
Add(textBoxes);
|
Add(textBoxes);
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
Size = new Vector2(100, 16),
|
Size = new Vector2(100, 16),
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
Text = @"Limited length",
|
Text = @"Limited length",
|
||||||
Size = new Vector2(200, 20),
|
Size = new Vector2(200, 20),
|
||||||
LengthLimit = 20,
|
LengthLimit = 20,
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
Text = @"Box with some more text",
|
Text = @"Box with some more text",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Placeholder text",
|
PlaceholderText = @"Placeholder text",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
Text = @"prefilled placeholder",
|
Text = @"prefilled placeholder",
|
||||||
PlaceholderText = @"Placeholder text",
|
PlaceholderText = @"Placeholder text",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
textBoxes.Add(new TextBox
|
textBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
Text = "Readonly textbox",
|
Text = "Readonly textbox",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
ReadOnly = true,
|
ReadOnly = true,
|
||||||
TabbableContentContainer = textBoxes
|
TabbableContentContainer = textBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
FillFlowContainer otherTextBoxes = new FillFlowContainer
|
FillFlowContainer otherTextBoxes = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 50),
|
Spacing = new Vector2(0, 50),
|
||||||
Padding = new MarginPadding
|
Padding = new MarginPadding
|
||||||
{
|
{
|
||||||
Top = 50,
|
Top = 50,
|
||||||
Left = 500
|
Left = 500
|
||||||
},
|
},
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.8f, 1)
|
Size = new Vector2(0.8f, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
otherTextBoxes.Add(new TextBox
|
otherTextBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Textbox in separate container",
|
PlaceholderText = @"Textbox in separate container",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
TabbableContentContainer = otherTextBoxes
|
TabbableContentContainer = otherTextBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
otherTextBoxes.Add(new PasswordTextBox
|
otherTextBoxes.Add(new PasswordTextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Password textbox",
|
PlaceholderText = @"Password textbox",
|
||||||
Text = "Secret ;)",
|
Text = "Secret ;)",
|
||||||
Size = new Vector2(500, 30),
|
Size = new Vector2(500, 30),
|
||||||
TabbableContentContainer = otherTextBoxes
|
TabbableContentContainer = otherTextBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
FillFlowContainer nestedTextBoxes = new FillFlowContainer
|
FillFlowContainer nestedTextBoxes = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 50),
|
Spacing = new Vector2(0, 50),
|
||||||
Margin = new MarginPadding { Left = 50 },
|
Margin = new MarginPadding { Left = 50 },
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.8f, 1)
|
Size = new Vector2(0.8f, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
nestedTextBoxes.Add(new TextBox
|
nestedTextBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Nested textbox 1",
|
PlaceholderText = @"Nested textbox 1",
|
||||||
Size = new Vector2(457, 30),
|
Size = new Vector2(457, 30),
|
||||||
TabbableContentContainer = otherTextBoxes
|
TabbableContentContainer = otherTextBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
nestedTextBoxes.Add(new TextBox
|
nestedTextBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Nested textbox 2",
|
PlaceholderText = @"Nested textbox 2",
|
||||||
Size = new Vector2(457, 30),
|
Size = new Vector2(457, 30),
|
||||||
TabbableContentContainer = otherTextBoxes
|
TabbableContentContainer = otherTextBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
nestedTextBoxes.Add(new TextBox
|
nestedTextBoxes.Add(new TextBox
|
||||||
{
|
{
|
||||||
PlaceholderText = @"Nested textbox 3",
|
PlaceholderText = @"Nested textbox 3",
|
||||||
Size = new Vector2(457, 30),
|
Size = new Vector2(457, 30),
|
||||||
TabbableContentContainer = otherTextBoxes
|
TabbableContentContainer = otherTextBoxes
|
||||||
});
|
});
|
||||||
|
|
||||||
otherTextBoxes.Add(nestedTextBoxes);
|
otherTextBoxes.Add(nestedTextBoxes);
|
||||||
|
|
||||||
Add(otherTextBoxes);
|
Add(otherTextBoxes);
|
||||||
|
|
||||||
//textBoxes.Add(tb = new PasswordTextBox(@"", 14, Vector2.Zero, 300));
|
//textBoxes.Add(tb = new PasswordTextBox(@"", 14, Vector2.Zero, 300));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,212 +1,212 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
[System.ComponentModel.Description("word-wrap and paragraphs")]
|
[System.ComponentModel.Description("word-wrap and paragraphs")]
|
||||||
public class TestCaseTextFlow : TestCase
|
public class TestCaseTextFlow : TestCase
|
||||||
{
|
{
|
||||||
public TestCaseTextFlow()
|
public TestCaseTextFlow()
|
||||||
{
|
{
|
||||||
FillFlowContainer flow;
|
FillFlowContainer flow;
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new ScrollContainer
|
new ScrollContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
flow = new FillFlowContainer
|
flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FillFlowContainer paragraphContainer;
|
FillFlowContainer paragraphContainer;
|
||||||
TextFlowContainer textFlowContainer;
|
TextFlowContainer textFlowContainer;
|
||||||
flow.Add(paragraphContainer = new FillFlowContainer
|
flow.Add(paragraphContainer = new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Width = 0.5f,
|
Width = 0.5f,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
textFlowContainer = new TextFlowContainer
|
textFlowContainer = new TextFlowContainer
|
||||||
{
|
{
|
||||||
FirstLineIndent = 5,
|
FirstLineIndent = 5,
|
||||||
ContentIndent = 10,
|
ContentIndent = 10,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
textFlowContainer.AddText("the considerably swift vermilion reynard bounds above the slothful mahogany hound.", t => t.Colour = Color4.Yellow);
|
textFlowContainer.AddText("the considerably swift vermilion reynard bounds above the slothful mahogany hound.", t => t.Colour = Color4.Yellow);
|
||||||
textFlowContainer.AddText("\nTHE ", t => t.Colour = Color4.Red);
|
textFlowContainer.AddText("\nTHE ", t => t.Colour = Color4.Red);
|
||||||
textFlowContainer.AddText("CONSIDERABLY", t => t.Colour = Color4.Pink);
|
textFlowContainer.AddText("CONSIDERABLY", t => t.Colour = Color4.Pink);
|
||||||
textFlowContainer.AddText(" SWIFT VERMILION REYNARD BOUNDS ABOVE THE SLOTHFUL MAHOGANY HOUND!!", t => t.Colour = Color4.Red);
|
textFlowContainer.AddText(" SWIFT VERMILION REYNARD BOUNDS ABOVE THE SLOTHFUL MAHOGANY HOUND!!", t => t.Colour = Color4.Red);
|
||||||
textFlowContainer.AddText("\n\n0123456789!@#$%^&*()_-+-[]{}.,<>;'\\\\", t => t.Colour = Color4.Blue);
|
textFlowContainer.AddText("\n\n0123456789!@#$%^&*()_-+-[]{}.,<>;'\\\\", t => t.Colour = Color4.Blue);
|
||||||
var textSize = 48f;
|
var textSize = 48f;
|
||||||
textFlowContainer.AddParagraph("Multiple Text Sizes", t =>
|
textFlowContainer.AddParagraph("Multiple Text Sizes", t =>
|
||||||
{
|
{
|
||||||
t.TextSize = textSize;
|
t.TextSize = textSize;
|
||||||
textSize -= 12f;
|
textSize -= 12f;
|
||||||
});
|
});
|
||||||
textFlowContainer.AddText("\nI'm a paragraph\nnewlines are cool", t => t.Colour = Color4.Beige);
|
textFlowContainer.AddText("\nI'm a paragraph\nnewlines are cool", t => t.Colour = Color4.Beige);
|
||||||
textFlowContainer.AddText(" (and so are inline styles!)", t => t.Colour = Color4.Yellow);
|
textFlowContainer.AddText(" (and so are inline styles!)", t => t.Colour = Color4.Yellow);
|
||||||
textFlowContainer.AddParagraph("There's 2 line breaks\n\ninside this paragraph!", t => t.Colour = Color4.GreenYellow);
|
textFlowContainer.AddParagraph("There's 2 line breaks\n\ninside this paragraph!", t => t.Colour = Color4.GreenYellow);
|
||||||
textFlowContainer.AddParagraph("Make\nTextFlowContainer\ngreat\nagain!", t => t.Colour = Color4.Red);
|
textFlowContainer.AddParagraph("Make\nTextFlowContainer\ngreat\nagain!", t => t.Colour = Color4.Red);
|
||||||
|
|
||||||
paragraphContainer.Add(new TextFlowContainer
|
paragraphContainer.Add(new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Text =
|
Text =
|
||||||
@"osu! is a freeware rhythm game developed by Dean ""peppy"" Herbert, originally for Microsoft Windows. The game has also been ported to macOS, iOS, Android, and Windows Phone.[1] Its game play is based on commercial titles including Osu! Tatakae! Ouendan, Elite Beat Agents, Taiko no Tatsujin, beatmania IIDX, O2Jam, and DJMax.
|
@"osu! is a freeware rhythm game developed by Dean ""peppy"" Herbert, originally for Microsoft Windows. The game has also been ported to macOS, iOS, Android, and Windows Phone.[1] Its game play is based on commercial titles including Osu! Tatakae! Ouendan, Elite Beat Agents, Taiko no Tatsujin, beatmania IIDX, O2Jam, and DJMax.
|
||||||
|
|
||||||
osu! is written in C# on the .NET Framework. On August 28, 2016, osu!'s source code was open-sourced under the MIT License. [2] [3] Dubbed as ""Lazer"", the project aims to make osu! available to more platforms and transparent. [4] The community includes over 9 million registered users, with a total of 6 billion ranked plays.[5]"
|
osu! is written in C# on the .NET Framework. On August 28, 2016, osu!'s source code was open-sourced under the MIT License. [2] [3] Dubbed as ""Lazer"", the project aims to make osu! available to more platforms and transparent. [4] The community includes over 9 million registered users, with a total of 6 billion ranked plays.[5]"
|
||||||
});
|
});
|
||||||
|
|
||||||
paragraphContainer.Add(new TestCaseCustomText
|
paragraphContainer.Add(new TestCaseCustomText
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Placeholders = new Drawable[]
|
Placeholders = new Drawable[]
|
||||||
{
|
{
|
||||||
new LineBaseBox
|
new LineBaseBox
|
||||||
{
|
{
|
||||||
Colour = Color4.Purple,
|
Colour = Color4.Purple,
|
||||||
LineBaseHeight = 25f,
|
LineBaseHeight = 25f,
|
||||||
Size = new Vector2(25, 25)
|
Size = new Vector2(25, 25)
|
||||||
}.WithEffect(new OutlineEffect
|
}.WithEffect(new OutlineEffect
|
||||||
{
|
{
|
||||||
Strength = 20f,
|
Strength = 20f,
|
||||||
PadExtent = true,
|
PadExtent = true,
|
||||||
BlurSigma = new Vector2(5f),
|
BlurSigma = new Vector2(5f),
|
||||||
Colour = Color4.White
|
Colour = Color4.White
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Text = "Test icons [RedBox] interleaved\n[GreenBox] with other [0] text, also [[0]] escaping stuff is possible."
|
Text = "Test icons [RedBox] interleaved\n[GreenBox] with other [0] text, also [[0]] escaping stuff is possible."
|
||||||
});
|
});
|
||||||
|
|
||||||
paragraphContainer.Add(new Container
|
paragraphContainer.Add(new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(300),
|
Size = new Vector2(300),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Name = "Background",
|
Name = "Background",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Alpha = 0.1f
|
Alpha = 0.1f
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.TopLeft,
|
TextAnchor = Anchor.TopLeft,
|
||||||
Text = "TopLeft"
|
Text = "TopLeft"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.TopCentre,
|
TextAnchor = Anchor.TopCentre,
|
||||||
Text = "TopCentre"
|
Text = "TopCentre"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.TopRight,
|
TextAnchor = Anchor.TopRight,
|
||||||
Text = "TopRight"
|
Text = "TopRight"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.BottomLeft,
|
TextAnchor = Anchor.BottomLeft,
|
||||||
Text = "BottomLeft"
|
Text = "BottomLeft"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.BottomCentre,
|
TextAnchor = Anchor.BottomCentre,
|
||||||
Text = "BottomCentre"
|
Text = "BottomCentre"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.BottomRight,
|
TextAnchor = Anchor.BottomRight,
|
||||||
Text = "BottomRight"
|
Text = "BottomRight"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.CentreLeft,
|
TextAnchor = Anchor.CentreLeft,
|
||||||
Text = "CentreLeft"
|
Text = "CentreLeft"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.Centre,
|
TextAnchor = Anchor.Centre,
|
||||||
Text = "Centre"
|
Text = "Centre"
|
||||||
},
|
},
|
||||||
new TextFlowContainer
|
new TextFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
TextAnchor = Anchor.CentreRight,
|
TextAnchor = Anchor.CentreRight,
|
||||||
Text = "CentreRight"
|
Text = "CentreRight"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep(@"resize paragraph 1", () => { paragraphContainer.Width = 1f; });
|
AddStep(@"resize paragraph 1", () => { paragraphContainer.Width = 1f; });
|
||||||
AddStep(@"resize paragraph 2", () => { paragraphContainer.Width = 0.6f; });
|
AddStep(@"resize paragraph 2", () => { paragraphContainer.Width = 0.6f; });
|
||||||
AddStep(@"header inset", () => { textFlowContainer.FirstLineIndent += 2; });
|
AddStep(@"header inset", () => { textFlowContainer.FirstLineIndent += 2; });
|
||||||
AddStep(@"body inset", () => { textFlowContainer.ContentIndent += 4; });
|
AddStep(@"body inset", () => { textFlowContainer.ContentIndent += 4; });
|
||||||
AddToggleStep(@"Zero paragraph spacing", state => textFlowContainer.ParagraphSpacing = state ? 0 : 0.5f);
|
AddToggleStep(@"Zero paragraph spacing", state => textFlowContainer.ParagraphSpacing = state ? 0 : 0.5f);
|
||||||
AddToggleStep(@"Non-zero line spacing", state => textFlowContainer.LineSpacing = state ? 1 : 0);
|
AddToggleStep(@"Non-zero line spacing", state => textFlowContainer.LineSpacing = state ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LineBaseBox : Box, IHasLineBaseHeight
|
private class LineBaseBox : Box, IHasLineBaseHeight
|
||||||
{
|
{
|
||||||
public float LineBaseHeight { get; set; }
|
public float LineBaseHeight { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestCaseCustomText : CustomizableTextContainer
|
private class TestCaseCustomText : CustomizableTextContainer
|
||||||
{
|
{
|
||||||
public TestCaseCustomText()
|
public TestCaseCustomText()
|
||||||
{
|
{
|
||||||
AddIconFactory("RedBox", makeRedBox);
|
AddIconFactory("RedBox", makeRedBox);
|
||||||
AddIconFactory("GreenBox", makeGreenBox);
|
AddIconFactory("GreenBox", makeGreenBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable makeGreenBox() => new LineBaseBox
|
private Drawable makeGreenBox() => new LineBaseBox
|
||||||
{
|
{
|
||||||
Colour = Color4.Green,
|
Colour = Color4.Green,
|
||||||
LineBaseHeight = 25f,
|
LineBaseHeight = 25f,
|
||||||
Size = new Vector2(25, 20)
|
Size = new Vector2(25, 20)
|
||||||
};
|
};
|
||||||
|
|
||||||
private Drawable makeRedBox() => new LineBaseBox
|
private Drawable makeRedBox() => new LineBaseBox
|
||||||
{
|
{
|
||||||
Colour = Color4.Red,
|
Colour = Color4.Red,
|
||||||
LineBaseHeight = 10f,
|
LineBaseHeight = 10f,
|
||||||
Size = new Vector2(25, 25)
|
Size = new Vector2(25, 25)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,212 +1,212 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTooltip : TestCase
|
public class TestCaseTooltip : TestCase
|
||||||
{
|
{
|
||||||
private readonly Container testContainer;
|
private readonly Container testContainer;
|
||||||
|
|
||||||
public TestCaseTooltip()
|
public TestCaseTooltip()
|
||||||
{
|
{
|
||||||
Add(testContainer = new Container
|
Add(testContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
});
|
});
|
||||||
|
|
||||||
AddToggleStep("Cursor-less tooltip", generateTest);
|
AddToggleStep("Cursor-less tooltip", generateTest);
|
||||||
generateTest(false);
|
generateTest(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TooltipBox makeBox(Anchor anchor)
|
private TooltipBox makeBox(Anchor anchor)
|
||||||
{
|
{
|
||||||
return new TooltipBox
|
return new TooltipBox
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.2f),
|
Size = new Vector2(0.2f),
|
||||||
Anchor = anchor,
|
Anchor = anchor,
|
||||||
Origin = anchor,
|
Origin = anchor,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
TooltipText = $"{anchor}",
|
TooltipText = $"{anchor}",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateTest(bool cursorlessTooltip)
|
private void generateTest(bool cursorlessTooltip)
|
||||||
{
|
{
|
||||||
testContainer.Clear();
|
testContainer.Clear();
|
||||||
|
|
||||||
CursorContainer cursor = null;
|
CursorContainer cursor = null;
|
||||||
if (!cursorlessTooltip)
|
if (!cursorlessTooltip)
|
||||||
{
|
{
|
||||||
cursor = new RectangleCursorContainer();
|
cursor = new RectangleCursorContainer();
|
||||||
testContainer.Add(cursor);
|
testContainer.Add(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
TooltipContainer ttc;
|
TooltipContainer ttc;
|
||||||
testContainer.Add(ttc = new TooltipContainer(cursor)
|
testContainer.Add(ttc = new TooltipContainer(cursor)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new TooltipBox
|
new TooltipBox
|
||||||
{
|
{
|
||||||
TooltipText = "Outer Tooltip",
|
TooltipText = "Outer Tooltip",
|
||||||
Colour = Color4.CornflowerBlue,
|
Colour = Color4.CornflowerBlue,
|
||||||
Size = new Vector2(300, 300),
|
Size = new Vector2(300, 300),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
},
|
},
|
||||||
new TooltipBox
|
new TooltipBox
|
||||||
{
|
{
|
||||||
TooltipText = "Inner Tooltip",
|
TooltipText = "Inner Tooltip",
|
||||||
Size = new Vector2(150, 150),
|
Size = new Vector2(150, 150),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 10),
|
Spacing = new Vector2(0, 10),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TooltipSpriteText("this text has a tooltip!"),
|
new TooltipSpriteText("this text has a tooltip!"),
|
||||||
new TooltipSpriteText("this one too!"),
|
new TooltipSpriteText("this one too!"),
|
||||||
new CustomTooltipSpriteText("this text has an empty tooltip!", string.Empty),
|
new CustomTooltipSpriteText("this text has an empty tooltip!", string.Empty),
|
||||||
new CustomTooltipSpriteText("this text has a nulled tooltip!", null),
|
new CustomTooltipSpriteText("this text has a nulled tooltip!", null),
|
||||||
new TooltipTextbox
|
new TooltipTextbox
|
||||||
{
|
{
|
||||||
Text = "with real time updates!",
|
Text = "with real time updates!",
|
||||||
Size = new Vector2(400, 30),
|
Size = new Vector2(400, 30),
|
||||||
},
|
},
|
||||||
new TooltipContainer
|
new TooltipContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new TooltipSpriteText("Nested tooltip; uses no cursor in all cases!"),
|
Child = new TooltipSpriteText("Nested tooltip; uses no cursor in all cases!"),
|
||||||
},
|
},
|
||||||
new TooltipTooltipContainer("This tooltip container has a tooltip itself!")
|
new TooltipTooltipContainer("This tooltip container has a tooltip itself!")
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Child = new TooltipSpriteText("Nested tooltip; uses no cursor in all cases; parent TooltipContainer has a tooltip"),
|
Child = new TooltipSpriteText("Nested tooltip; uses no cursor in all cases; parent TooltipContainer has a tooltip"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Child = new FillFlowContainer
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 8),
|
Spacing = new Vector2(0, 8),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Child = new Container
|
Child = new Container
|
||||||
{
|
{
|
||||||
Child = new TooltipSpriteText("Tooltip within containers with zero size; i.e. parent is never hovered."),
|
Child = new TooltipSpriteText("Tooltip within containers with zero size; i.e. parent is never hovered."),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Child = new TooltipSpriteText("Other tooltip within containers with zero size; different nesting; overlap."),
|
Child = new TooltipSpriteText("Other tooltip within containers with zero size; different nesting; overlap."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ttc.Add(makeBox(Anchor.BottomLeft));
|
ttc.Add(makeBox(Anchor.BottomLeft));
|
||||||
ttc.Add(makeBox(Anchor.TopRight));
|
ttc.Add(makeBox(Anchor.TopRight));
|
||||||
ttc.Add(makeBox(Anchor.BottomRight));
|
ttc.Add(makeBox(Anchor.BottomRight));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CustomTooltipSpriteText : Container, IHasTooltip
|
private class CustomTooltipSpriteText : Container, IHasTooltip
|
||||||
{
|
{
|
||||||
private readonly string tooltipText;
|
private readonly string tooltipText;
|
||||||
|
|
||||||
public string TooltipText => tooltipText;
|
public string TooltipText => tooltipText;
|
||||||
|
|
||||||
public CustomTooltipSpriteText(string displayedText, string tooltipText)
|
public CustomTooltipSpriteText(string displayedText, string tooltipText)
|
||||||
{
|
{
|
||||||
this.tooltipText = tooltipText;
|
this.tooltipText = tooltipText;
|
||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = displayedText,
|
Text = displayedText,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TooltipSpriteText : CustomTooltipSpriteText
|
private class TooltipSpriteText : CustomTooltipSpriteText
|
||||||
{
|
{
|
||||||
public TooltipSpriteText(string tooltipText)
|
public TooltipSpriteText(string tooltipText)
|
||||||
: base(tooltipText, tooltipText)
|
: base(tooltipText, tooltipText)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TooltipTooltipContainer : TooltipContainer, IHasTooltip
|
private class TooltipTooltipContainer : TooltipContainer, IHasTooltip
|
||||||
{
|
{
|
||||||
public string TooltipText { get; set; }
|
public string TooltipText { get; set; }
|
||||||
|
|
||||||
public TooltipTooltipContainer(string tooltipText)
|
public TooltipTooltipContainer(string tooltipText)
|
||||||
{
|
{
|
||||||
TooltipText = tooltipText;
|
TooltipText = tooltipText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TooltipTextbox : TextBox, IHasTooltip
|
private class TooltipTextbox : TextBox, IHasTooltip
|
||||||
{
|
{
|
||||||
public string TooltipText => Text;
|
public string TooltipText => Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TooltipBox : Box, IHasTooltip
|
private class TooltipBox : Box, IHasTooltip
|
||||||
{
|
{
|
||||||
public string TooltipText { get; set; }
|
public string TooltipText { get; set; }
|
||||||
|
|
||||||
public override bool HandleKeyboardInput => true;
|
public override bool HandleKeyboardInput => true;
|
||||||
public override bool HandleMouseInput => true;
|
public override bool HandleMouseInput => true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RectangleCursorContainer : CursorContainer
|
private class RectangleCursorContainer : CursorContainer
|
||||||
{
|
{
|
||||||
protected override Drawable CreateCursor() => new RectangleCursor();
|
protected override Drawable CreateCursor() => new RectangleCursor();
|
||||||
|
|
||||||
private class RectangleCursor : Box
|
private class RectangleCursor : Box
|
||||||
{
|
{
|
||||||
public RectangleCursor()
|
public RectangleCursor()
|
||||||
{
|
{
|
||||||
Size = new Vector2(20, 40);
|
Size = new Vector2(20, 40);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,385 +1,385 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTransformRewinding : TestCase
|
public class TestCaseTransformRewinding : TestCase
|
||||||
{
|
{
|
||||||
private const double interval = 250;
|
private const double interval = 250;
|
||||||
private const int interval_count = 4;
|
private const int interval_count = 4;
|
||||||
|
|
||||||
private static double intervalAt(int sequence) => interval * sequence;
|
private static double intervalAt(int sequence) => interval * sequence;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
AddStep("Basic scale", () => boxTest(box =>
|
AddStep("Basic scale", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.Scale = Vector2.One;
|
box.Scale = Vector2.One;
|
||||||
box.ScaleTo(0, interval * 4);
|
box.ScaleTo(0, interval * 4);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Scale sequence", () => boxTest(box =>
|
AddStep("Scale sequence", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.Scale = Vector2.One;
|
box.Scale = Vector2.One;
|
||||||
|
|
||||||
box.ScaleTo(0.75f, interval).Then()
|
box.ScaleTo(0.75f, interval).Then()
|
||||||
.ScaleTo(0.5f, interval).Then()
|
.ScaleTo(0.5f, interval).Then()
|
||||||
.ScaleTo(0.25f, interval).Then()
|
.ScaleTo(0.25f, interval).Then()
|
||||||
.ScaleTo(0, interval);
|
.ScaleTo(0, interval);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Basic movement", () => boxTest(box =>
|
AddStep("Basic movement", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.Scale = new Vector2(0.25f);
|
box.Scale = new Vector2(0.25f);
|
||||||
box.Anchor = Anchor.TopLeft;
|
box.Anchor = Anchor.TopLeft;
|
||||||
box.Origin = Anchor.TopLeft;
|
box.Origin = Anchor.TopLeft;
|
||||||
|
|
||||||
box.MoveTo(new Vector2(0.75f, 0), interval).Then()
|
box.MoveTo(new Vector2(0.75f, 0), interval).Then()
|
||||||
.MoveTo(new Vector2(0.75f, 0.75f), interval).Then()
|
.MoveTo(new Vector2(0.75f, 0.75f), interval).Then()
|
||||||
.MoveTo(new Vector2(0, 0.75f), interval).Then()
|
.MoveTo(new Vector2(0, 0.75f), interval).Then()
|
||||||
.MoveTo(new Vector2(0), interval);
|
.MoveTo(new Vector2(0), interval);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Move sequence", () => boxTest(box =>
|
AddStep("Move sequence", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.Scale = new Vector2(0.25f);
|
box.Scale = new Vector2(0.25f);
|
||||||
box.Anchor = Anchor.TopLeft;
|
box.Anchor = Anchor.TopLeft;
|
||||||
box.Origin = Anchor.TopLeft;
|
box.Origin = Anchor.TopLeft;
|
||||||
|
|
||||||
box.ScaleTo(0.5f, interval).MoveTo(new Vector2(0.5f), interval)
|
box.ScaleTo(0.5f, interval).MoveTo(new Vector2(0.5f), interval)
|
||||||
.Then()
|
.Then()
|
||||||
.ScaleTo(0.1f, interval).MoveTo(new Vector2(0, 0.75f), interval)
|
.ScaleTo(0.1f, interval).MoveTo(new Vector2(0, 0.75f), interval)
|
||||||
.Then()
|
.Then()
|
||||||
.ScaleTo(1f, interval).MoveTo(new Vector2(0, 0), interval)
|
.ScaleTo(1f, interval).MoveTo(new Vector2(0, 0), interval)
|
||||||
.Then()
|
.Then()
|
||||||
.FadeTo(0, interval);
|
.FadeTo(0, interval);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Same type in type", () => boxTest(box =>
|
AddStep("Same type in type", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.ScaleTo(0.5f, interval * 4);
|
box.ScaleTo(0.5f, interval * 4);
|
||||||
box.Delay(interval * 2).ScaleTo(1, interval);
|
box.Delay(interval * 2).ScaleTo(1, interval);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Same type partial overlap", () => boxTest(box =>
|
AddStep("Same type partial overlap", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.ScaleTo(0.5f, interval * 2);
|
box.ScaleTo(0.5f, interval * 2);
|
||||||
box.Delay(interval).ScaleTo(1, interval * 2);
|
box.Delay(interval).ScaleTo(1, interval * 2);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
AddStep("Start in middle of sequence", () => boxTest(box =>
|
AddStep("Start in middle of sequence", () => boxTest(box =>
|
||||||
{
|
{
|
||||||
box.Alpha = 0;
|
box.Alpha = 0;
|
||||||
box.Delay(interval * 2).FadeInFromZero(interval);
|
box.Delay(interval * 2).FadeInFromZero(interval);
|
||||||
box.ScaleTo(0.9f, interval * 4);
|
box.ScaleTo(0.9f, interval * 4);
|
||||||
}, 750));
|
}, 750));
|
||||||
|
|
||||||
AddStep("Loop sequence", () => boxTest(box => { box.RotateTo(0).RotateTo(90, interval).Loop(); }));
|
AddStep("Loop sequence", () => boxTest(box => { box.RotateTo(0).RotateTo(90, interval).Loop(); }));
|
||||||
|
|
||||||
AddStep("Start in middle of loop sequence", () => boxTest(box => { box.RotateTo(0).RotateTo(90, interval).Loop(); }, 750));
|
AddStep("Start in middle of loop sequence", () => boxTest(box => { box.RotateTo(0).RotateTo(90, interval).Loop(); }, 750));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Box box;
|
private Box box;
|
||||||
|
|
||||||
private void boxTest(Action<Box> action, int startTime = 0)
|
private void boxTest(Action<Box> action, int startTime = 0)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
Add(new AnimationContainer(startTime)
|
Add(new AnimationContainer(startTime)
|
||||||
{
|
{
|
||||||
Child = box = new Box
|
Child = box = new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
Scale = new Vector2(0.25f),
|
Scale = new Vector2(0.25f),
|
||||||
},
|
},
|
||||||
ExaminableDrawable = box,
|
ExaminableDrawable = box,
|
||||||
});
|
});
|
||||||
|
|
||||||
action(box);
|
action(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AnimationContainer : Container
|
private class AnimationContainer : Container
|
||||||
{
|
{
|
||||||
public override bool RemoveCompletedTransforms => false;
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
protected override Container<Drawable> Content => content;
|
protected override Container<Drawable> Content => content;
|
||||||
private readonly Container content;
|
private readonly Container content;
|
||||||
|
|
||||||
private readonly SpriteText minTimeText;
|
private readonly SpriteText minTimeText;
|
||||||
private readonly SpriteText currentTimeText;
|
private readonly SpriteText currentTimeText;
|
||||||
private readonly SpriteText maxTimeText;
|
private readonly SpriteText maxTimeText;
|
||||||
|
|
||||||
private readonly Tick seekingTick;
|
private readonly Tick seekingTick;
|
||||||
private readonly WrappingTimeContainer wrapping;
|
private readonly WrappingTimeContainer wrapping;
|
||||||
|
|
||||||
public Box ExaminableDrawable;
|
public Box ExaminableDrawable;
|
||||||
|
|
||||||
private readonly FlowContainer<DrawableTransform> transforms;
|
private readonly FlowContainer<DrawableTransform> transforms;
|
||||||
|
|
||||||
public AnimationContainer(int startTime = 0)
|
public AnimationContainer(int startTime = 0)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChild = wrapping = new WrappingTimeContainer(startTime)
|
InternalChild = wrapping = new WrappingTimeContainer(startTime)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
FillMode = FillMode.Fit,
|
FillMode = FillMode.Fit,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Size = new Vector2(0.6f),
|
Size = new Vector2(0.6f),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.DarkGray,
|
Colour = Color4.DarkGray,
|
||||||
},
|
},
|
||||||
content = new Container
|
content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transforms = new FillFlowContainer<DrawableTransform>
|
transforms = new FillFlowContainer<DrawableTransform>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Spacing = Vector2.One,
|
Spacing = Vector2.One,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.8f, 0.1f),
|
Size = new Vector2(0.8f, 0.1f),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
minTimeText = new SpriteText
|
minTimeText = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
},
|
},
|
||||||
currentTimeText = new SpriteText
|
currentTimeText = new SpriteText
|
||||||
{
|
{
|
||||||
RelativePositionAxes = Axes.X,
|
RelativePositionAxes = Axes.X,
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Y = -10,
|
Y = -10,
|
||||||
},
|
},
|
||||||
maxTimeText = new SpriteText
|
maxTimeText = new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
},
|
},
|
||||||
seekingTick = new Tick(0, false),
|
seekingTick = new Tick(0, false),
|
||||||
new Tick(0),
|
new Tick(0),
|
||||||
new Tick(1),
|
new Tick(1),
|
||||||
new Tick(2),
|
new Tick(2),
|
||||||
new Tick(3),
|
new Tick(3),
|
||||||
new Tick(4),
|
new Tick(4),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private int displayedTransformsCount;
|
private int displayedTransformsCount;
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
double time = wrapping.Time.Current;
|
double time = wrapping.Time.Current;
|
||||||
|
|
||||||
minTimeText.Text = wrapping.MinTime.ToString("n0");
|
minTimeText.Text = wrapping.MinTime.ToString("n0");
|
||||||
currentTimeText.Text = time.ToString("n0");
|
currentTimeText.Text = time.ToString("n0");
|
||||||
seekingTick.X = currentTimeText.X = (float)(time / (wrapping.MaxTime - wrapping.MinTime));
|
seekingTick.X = currentTimeText.X = (float)(time / (wrapping.MaxTime - wrapping.MinTime));
|
||||||
maxTimeText.Text = wrapping.MaxTime.ToString("n0");
|
maxTimeText.Text = wrapping.MaxTime.ToString("n0");
|
||||||
|
|
||||||
maxTimeText.Colour = time > wrapping.MaxTime ? Color4.Gray : (wrapping.Time.Elapsed > 0 ? Color4.Blue : Color4.Red);
|
maxTimeText.Colour = time > wrapping.MaxTime ? Color4.Gray : (wrapping.Time.Elapsed > 0 ? Color4.Blue : Color4.Red);
|
||||||
minTimeText.Colour = time < wrapping.MinTime ? Color4.Gray : (content.Time.Elapsed > 0 ? Color4.Blue : Color4.Red);
|
minTimeText.Colour = time < wrapping.MinTime ? Color4.Gray : (content.Time.Elapsed > 0 ? Color4.Blue : Color4.Red);
|
||||||
|
|
||||||
if (ExaminableDrawable.Transforms.Count != displayedTransformsCount)
|
if (ExaminableDrawable.Transforms.Count != displayedTransformsCount)
|
||||||
{
|
{
|
||||||
transforms.Clear();
|
transforms.Clear();
|
||||||
foreach (var t in ExaminableDrawable.Transforms)
|
foreach (var t in ExaminableDrawable.Transforms)
|
||||||
transforms.Add(new DrawableTransform(t));
|
transforms.Add(new DrawableTransform(t));
|
||||||
displayedTransformsCount = ExaminableDrawable.Transforms.Count;
|
displayedTransformsCount = ExaminableDrawable.Transforms.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DrawableTransform : CompositeDrawable
|
private class DrawableTransform : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly Transform transform;
|
private readonly Transform transform;
|
||||||
private readonly Box applied;
|
private readonly Box applied;
|
||||||
private readonly Box appliedToEnd;
|
private readonly Box appliedToEnd;
|
||||||
private readonly SpriteText text;
|
private readonly SpriteText text;
|
||||||
|
|
||||||
private const float height = 15;
|
private const float height = 15;
|
||||||
|
|
||||||
public DrawableTransform(Transform transform)
|
public DrawableTransform(Transform transform)
|
||||||
{
|
{
|
||||||
this.transform = transform;
|
this.transform = transform;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = height;
|
Height = height;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
applied = new Box { Size = new Vector2(height) },
|
applied = new Box { Size = new Vector2(height) },
|
||||||
appliedToEnd = new Box { X = height + 2, Size = new Vector2(height) },
|
appliedToEnd = new Box { X = height + 2, Size = new Vector2(height) },
|
||||||
text = new SpriteText { X = (height + 2) * 2, TextSize = height },
|
text = new SpriteText { X = (height + 2) * 2, TextSize = height },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
applied.Colour = transform.Applied ? Color4.Green : Color4.Red;
|
applied.Colour = transform.Applied ? Color4.Green : Color4.Red;
|
||||||
appliedToEnd.Colour = transform.AppliedToEnd ? Color4.Green : Color4.Red;
|
appliedToEnd.Colour = transform.AppliedToEnd ? Color4.Green : Color4.Red;
|
||||||
text.Text = transform.ToString();
|
text.Text = transform.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Tick : Box
|
private class Tick : Box
|
||||||
{
|
{
|
||||||
private readonly int tick;
|
private readonly int tick;
|
||||||
private readonly bool colouring;
|
private readonly bool colouring;
|
||||||
|
|
||||||
public Tick(int tick, bool colouring = true)
|
public Tick(int tick, bool colouring = true)
|
||||||
{
|
{
|
||||||
this.tick = tick;
|
this.tick = tick;
|
||||||
this.colouring = colouring;
|
this.colouring = colouring;
|
||||||
Anchor = Anchor.BottomLeft;
|
Anchor = Anchor.BottomLeft;
|
||||||
Origin = Anchor.BottomCentre;
|
Origin = Anchor.BottomCentre;
|
||||||
|
|
||||||
Size = new Vector2(1, 10);
|
Size = new Vector2(1, 10);
|
||||||
Colour = Color4.White;
|
Colour = Color4.White;
|
||||||
|
|
||||||
RelativePositionAxes = Axes.X;
|
RelativePositionAxes = Axes.X;
|
||||||
X = (float)tick / interval_count;
|
X = (float)tick / interval_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (colouring)
|
if (colouring)
|
||||||
Colour = Time.Current > tick * interval ? Color4.Yellow : Color4.White;
|
Colour = Time.Current > tick * interval ? Color4.Yellow : Color4.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WrappingTimeContainer : Container
|
private class WrappingTimeContainer : Container
|
||||||
{
|
{
|
||||||
// Padding, in milliseconds, at each end of maxima of the clock time
|
// Padding, in milliseconds, at each end of maxima of the clock time
|
||||||
private const double time_padding = 50;
|
private const double time_padding = 50;
|
||||||
|
|
||||||
public double MinTime => clock.MinTime + time_padding;
|
public double MinTime => clock.MinTime + time_padding;
|
||||||
public double MaxTime => clock.MaxTime - time_padding;
|
public double MaxTime => clock.MaxTime - time_padding;
|
||||||
|
|
||||||
private readonly ReversibleClock clock;
|
private readonly ReversibleClock clock;
|
||||||
|
|
||||||
public WrappingTimeContainer(double startTime)
|
public WrappingTimeContainer(double startTime)
|
||||||
{
|
{
|
||||||
clock = new ReversibleClock(startTime);
|
clock = new ReversibleClock(startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
// Replace the game clock, but keep it as a reference
|
// Replace the game clock, but keep it as a reference
|
||||||
clock.SetSource(Clock);
|
clock.SetSource(Clock);
|
||||||
Clock = clock;
|
Clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
clock.MinTime = -time_padding;
|
clock.MinTime = -time_padding;
|
||||||
clock.MaxTime = intervalAt(interval_count) + time_padding;
|
clock.MaxTime = intervalAt(interval_count) + time_padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReversibleClock : IFrameBasedClock
|
private class ReversibleClock : IFrameBasedClock
|
||||||
{
|
{
|
||||||
private readonly double startTime;
|
private readonly double startTime;
|
||||||
public double MinTime;
|
public double MinTime;
|
||||||
public double MaxTime = 1000;
|
public double MaxTime = 1000;
|
||||||
|
|
||||||
private IFrameBasedClock trackingClock;
|
private IFrameBasedClock trackingClock;
|
||||||
|
|
||||||
private bool reversed;
|
private bool reversed;
|
||||||
|
|
||||||
public ReversibleClock(double startTime)
|
public ReversibleClock(double startTime)
|
||||||
{
|
{
|
||||||
this.startTime = startTime;
|
this.startTime = startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSource(IFrameBasedClock trackingClock)
|
public void SetSource(IFrameBasedClock trackingClock)
|
||||||
{
|
{
|
||||||
this.trackingClock = new FramedOffsetClock(trackingClock) { Offset = -trackingClock.CurrentTime + startTime };
|
this.trackingClock = new FramedOffsetClock(trackingClock) { Offset = -trackingClock.CurrentTime + startTime };
|
||||||
}
|
}
|
||||||
|
|
||||||
public double CurrentTime { get; private set; }
|
public double CurrentTime { get; private set; }
|
||||||
|
|
||||||
public double Rate => trackingClock.Rate;
|
public double Rate => trackingClock.Rate;
|
||||||
|
|
||||||
public bool IsRunning => trackingClock.IsRunning;
|
public bool IsRunning => trackingClock.IsRunning;
|
||||||
|
|
||||||
public double ElapsedFrameTime => (reversed ? -1 : 1) * trackingClock.ElapsedFrameTime;
|
public double ElapsedFrameTime => (reversed ? -1 : 1) * trackingClock.ElapsedFrameTime;
|
||||||
|
|
||||||
public double AverageFrameTime => trackingClock.AverageFrameTime;
|
public double AverageFrameTime => trackingClock.AverageFrameTime;
|
||||||
|
|
||||||
public double FramesPerSecond => trackingClock.FramesPerSecond;
|
public double FramesPerSecond => trackingClock.FramesPerSecond;
|
||||||
|
|
||||||
public FrameTimeInfo TimeInfo => new FrameTimeInfo { Current = CurrentTime, Elapsed = ElapsedFrameTime };
|
public FrameTimeInfo TimeInfo => new FrameTimeInfo { Current = CurrentTime, Elapsed = ElapsedFrameTime };
|
||||||
|
|
||||||
public void ProcessFrame()
|
public void ProcessFrame()
|
||||||
{
|
{
|
||||||
trackingClock.ProcessFrame();
|
trackingClock.ProcessFrame();
|
||||||
|
|
||||||
// There are two iterations, when iteration % 2 == 0 : not reversed
|
// There are two iterations, when iteration % 2 == 0 : not reversed
|
||||||
int iteration = (int)(trackingClock.CurrentTime / (MaxTime - MinTime));
|
int iteration = (int)(trackingClock.CurrentTime / (MaxTime - MinTime));
|
||||||
reversed = iteration % 2 == 1;
|
reversed = iteration % 2 == 1;
|
||||||
|
|
||||||
double iterationTime = trackingClock.CurrentTime % (MaxTime - MinTime);
|
double iterationTime = trackingClock.CurrentTime % (MaxTime - MinTime);
|
||||||
|
|
||||||
if (reversed)
|
if (reversed)
|
||||||
CurrentTime = MaxTime - iterationTime;
|
CurrentTime = MaxTime - iterationTime;
|
||||||
else
|
else
|
||||||
CurrentTime = MinTime + iterationTime;
|
CurrentTime = MinTime + iterationTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,178 +1,178 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Transforms;
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTransformSequence : GridTestCase
|
public class TestCaseTransformSequence : GridTestCase
|
||||||
{
|
{
|
||||||
private readonly Container[] boxes;
|
private readonly Container[] boxes;
|
||||||
|
|
||||||
public TestCaseTransformSequence()
|
public TestCaseTransformSequence()
|
||||||
: base(3, 3)
|
: base(3, 3)
|
||||||
{
|
{
|
||||||
boxes = new Container[Rows * Cols];
|
boxes = new Container[Rows * Cols];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
testFinish();
|
testFinish();
|
||||||
testClear();
|
testClear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testFinish()
|
private void testFinish()
|
||||||
{
|
{
|
||||||
AddStep("Animate", delegate
|
AddStep("Animate", delegate
|
||||||
{
|
{
|
||||||
setup();
|
setup();
|
||||||
animate();
|
animate();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep($"{nameof(FinishTransforms)}", delegate
|
AddStep($"{nameof(FinishTransforms)}", delegate
|
||||||
{
|
{
|
||||||
foreach (var box in boxes)
|
foreach (var box in boxes)
|
||||||
box.FinishTransforms();
|
box.FinishTransforms();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("finalize triggered", () => finalizeTriggered);
|
AddAssert("finalize triggered", () => finalizeTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testClear()
|
private void testClear()
|
||||||
{
|
{
|
||||||
AddStep("Animate", delegate
|
AddStep("Animate", delegate
|
||||||
{
|
{
|
||||||
setup();
|
setup();
|
||||||
animate();
|
animate();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddStep($"{nameof(ClearTransforms)}", delegate
|
AddStep($"{nameof(ClearTransforms)}", delegate
|
||||||
{
|
{
|
||||||
foreach (var box in boxes)
|
foreach (var box in boxes)
|
||||||
box.ClearTransforms();
|
box.ClearTransforms();
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("finalize triggered", () => finalizeTriggered);
|
AddAssert("finalize triggered", () => finalizeTriggered);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setup()
|
private void setup()
|
||||||
{
|
{
|
||||||
finalizeTriggered = false;
|
finalizeTriggered = false;
|
||||||
|
|
||||||
string[] labels =
|
string[] labels =
|
||||||
{
|
{
|
||||||
"Spin after 2 seconds",
|
"Spin after 2 seconds",
|
||||||
"Loop(1 sec pause; 1 sec rotate)",
|
"Loop(1 sec pause; 1 sec rotate)",
|
||||||
"Complex transform 1 (should end in sync with CT2)",
|
"Complex transform 1 (should end in sync with CT2)",
|
||||||
"Complex transform 2 (should end in sync with CT1)",
|
"Complex transform 2 (should end in sync with CT1)",
|
||||||
$"Red on {nameof(TransformSequence<Container>)}.{nameof(TransformSequence<Container>.OnAbort)}",
|
$"Red on {nameof(TransformSequence<Container>)}.{nameof(TransformSequence<Container>.OnAbort)}",
|
||||||
$"Red on {nameof(TransformSequence<Container>)}.{nameof(TransformSequence<Container>.Finally)}",
|
$"Red on {nameof(TransformSequence<Container>)}.{nameof(TransformSequence<Container>.Finally)}",
|
||||||
"Red after instant transform",
|
"Red after instant transform",
|
||||||
"Red after instant transform 1 sec in the past",
|
"Red after instant transform 1 sec in the past",
|
||||||
"Red after 1 sec transform 1 sec in the past",
|
"Red after 1 sec transform 1 sec in the past",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < Rows * Cols; ++i)
|
for (int i = 0; i < Rows * Cols; ++i)
|
||||||
{
|
{
|
||||||
Cell(i).Children = new Drawable[]
|
Cell(i).Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Text = labels[i],
|
Text = labels[i],
|
||||||
TextSize = 20,
|
TextSize = 20,
|
||||||
},
|
},
|
||||||
boxes[i] = new Container
|
boxes[i] = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Size = new Vector2(0.25f),
|
Size = new Vector2(0.25f),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
EdgeEffect = new EdgeEffectParameters
|
EdgeEffect = new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Type = EdgeEffectType.Glow,
|
Type = EdgeEffectType.Glow,
|
||||||
Radius = 20,
|
Radius = 20,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
},
|
},
|
||||||
Child = new Box
|
Child = new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool finalizeTriggered;
|
private bool finalizeTriggered;
|
||||||
|
|
||||||
private void animate()
|
private void animate()
|
||||||
{
|
{
|
||||||
boxes[0].Delay(500).Then(500).Then(500).Then(
|
boxes[0].Delay(500).Then(500).Then(500).Then(
|
||||||
b => b.Delay(500).Spin(1000, RotationDirection.CounterClockwise)
|
b => b.Delay(500).Spin(1000, RotationDirection.CounterClockwise)
|
||||||
);
|
);
|
||||||
|
|
||||||
boxes[1].Delay(1000).Loop(1000, 10, b => b.RotateTo(0).RotateTo(340, 1000));
|
boxes[1].Delay(1000).Loop(1000, 10, b => b.RotateTo(0).RotateTo(340, 1000));
|
||||||
|
|
||||||
boxes[2].RotateTo(0).ScaleTo(1).RotateTo(360, 1000)
|
boxes[2].RotateTo(0).ScaleTo(1).RotateTo(360, 1000)
|
||||||
.Then(1000,
|
.Then(1000,
|
||||||
b => b.RotateTo(0, 1000),
|
b => b.RotateTo(0, 1000),
|
||||||
b => b.ScaleTo(2, 500)
|
b => b.ScaleTo(2, 500)
|
||||||
)
|
)
|
||||||
.Then().RotateTo(360, 1000).ScaleTo(0.5f, 1000)
|
.Then().RotateTo(360, 1000).ScaleTo(0.5f, 1000)
|
||||||
.Then().FadeEdgeEffectTo(Color4.Red, 1000).ScaleTo(2, 500);
|
.Then().FadeEdgeEffectTo(Color4.Red, 1000).ScaleTo(2, 500);
|
||||||
|
|
||||||
boxes[3].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
boxes[3].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
||||||
.Then(1000,
|
.Then(1000,
|
||||||
b => b.RotateTo(0),
|
b => b.RotateTo(0),
|
||||||
b => b.ScaleTo(2)
|
b => b.ScaleTo(2)
|
||||||
)
|
)
|
||||||
.Then(
|
.Then(
|
||||||
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)).Delay(500).ScaleTo(0.5f, 500)
|
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)).Delay(500).ScaleTo(0.5f, 500)
|
||||||
)
|
)
|
||||||
.Then().FadeEdgeEffectTo(Color4.Red, 1000).ScaleTo(2, 500)
|
.Then().FadeEdgeEffectTo(Color4.Red, 1000).ScaleTo(2, 500)
|
||||||
.Finally(_ => finalizeTriggered = true);
|
.Finally(_ => finalizeTriggered = true);
|
||||||
|
|
||||||
|
|
||||||
boxes[4].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
boxes[4].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
||||||
.Then(1000,
|
.Then(1000,
|
||||||
b => b.RotateTo(0),
|
b => b.RotateTo(0),
|
||||||
b => b.ScaleTo(2)
|
b => b.ScaleTo(2)
|
||||||
)
|
)
|
||||||
.Then(
|
.Then(
|
||||||
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)),
|
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)),
|
||||||
b => b.ScaleTo(0.5f, 500)
|
b => b.ScaleTo(0.5f, 500)
|
||||||
)
|
)
|
||||||
.OnAbort(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
.OnAbort(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
||||||
|
|
||||||
|
|
||||||
boxes[5].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
boxes[5].RotateTo(0).ScaleTo(1).RotateTo(360, 500)
|
||||||
.Then(1000,
|
.Then(1000,
|
||||||
b => b.RotateTo(0),
|
b => b.RotateTo(0),
|
||||||
b => b.ScaleTo(2)
|
b => b.ScaleTo(2)
|
||||||
)
|
)
|
||||||
.Then(
|
.Then(
|
||||||
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)),
|
b => b.Loop(500, 2, d => d.RotateTo(0).RotateTo(360, 1000)),
|
||||||
b => b.ScaleTo(0.5f, 500)
|
b => b.ScaleTo(0.5f, 500)
|
||||||
)
|
)
|
||||||
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
||||||
|
|
||||||
boxes[6].RotateTo(200)
|
boxes[6].RotateTo(200)
|
||||||
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
||||||
|
|
||||||
boxes[7].Delay(-1000).RotateTo(200)
|
boxes[7].Delay(-1000).RotateTo(200)
|
||||||
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
||||||
|
|
||||||
boxes[8].Delay(-1000).RotateTo(200, 1000)
|
boxes[8].Delay(-1000).RotateTo(200, 1000)
|
||||||
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
.Finally(b => b.FadeEdgeEffectTo(Color4.Red, 1000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,189 +1,189 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseTriangles : TestCase
|
public class TestCaseTriangles : TestCase
|
||||||
{
|
{
|
||||||
private readonly Container testContainer;
|
private readonly Container testContainer;
|
||||||
|
|
||||||
public TestCaseTriangles()
|
public TestCaseTriangles()
|
||||||
{
|
{
|
||||||
Add(testContainer = new Container
|
Add(testContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
});
|
});
|
||||||
|
|
||||||
string[] testNames = { @"Bounding box / input" };
|
string[] testNames = { @"Bounding box / input" };
|
||||||
|
|
||||||
for (int i = 0; i < testNames.Length; i++)
|
for (int i = 0; i < testNames.Length; i++)
|
||||||
{
|
{
|
||||||
int test = i;
|
int test = i;
|
||||||
AddStep(testNames[i], delegate { loadTest(test); });
|
AddStep(testNames[i], delegate { loadTest(test); });
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTest(0);
|
loadTest(0);
|
||||||
addCrosshair();
|
addCrosshair();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCrosshair()
|
private void addCrosshair()
|
||||||
{
|
{
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Size = new Vector2(22, 4),
|
Size = new Vector2(22, 4),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Size = new Vector2(4, 22),
|
Size = new Vector2(4, 22),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.WhiteSmoke,
|
Colour = Color4.WhiteSmoke,
|
||||||
Size = new Vector2(20, 2),
|
Size = new Vector2(20, 2),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
Add(new Box
|
Add(new Box
|
||||||
{
|
{
|
||||||
Colour = Color4.WhiteSmoke,
|
Colour = Color4.WhiteSmoke,
|
||||||
Size = new Vector2(2, 20),
|
Size = new Vector2(2, 20),
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTest(int testType)
|
private void loadTest(int testType)
|
||||||
{
|
{
|
||||||
testContainer.Clear();
|
testContainer.Clear();
|
||||||
|
|
||||||
Triangle triangle;
|
Triangle triangle;
|
||||||
|
|
||||||
switch (testType)
|
switch (testType)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
Container box;
|
Container box;
|
||||||
|
|
||||||
testContainer.Add(box = new InfofulBoxAutoSize
|
testContainer.Add(box = new InfofulBoxAutoSize
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
});
|
});
|
||||||
|
|
||||||
addCornerMarkers(box);
|
addCornerMarkers(box);
|
||||||
|
|
||||||
box.AddRange(new[]
|
box.AddRange(new[]
|
||||||
{
|
{
|
||||||
new DraggableTriangle
|
new DraggableTriangle
|
||||||
{
|
{
|
||||||
//chameleon = true,
|
//chameleon = true,
|
||||||
Position = new Vector2(0, 0),
|
Position = new Vector2(0, 0),
|
||||||
Size = new Vector2(25, 25),
|
Size = new Vector2(25, 25),
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.Blue,
|
Colour = Color4.Blue,
|
||||||
},
|
},
|
||||||
triangle = new DraggableTriangle
|
triangle = new DraggableTriangle
|
||||||
{
|
{
|
||||||
Size = new Vector2(250, 250),
|
Size = new Vector2(250, 250),
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Colour = Color4.DarkSeaGreen,
|
Colour = Color4.DarkSeaGreen,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
triangle.OnUpdate += delegate { triangle.Rotation += 0.05f; };
|
triangle.OnUpdate += delegate { triangle.Rotation += 0.05f; };
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
//if (toggleDebugAutosize.State)
|
//if (toggleDebugAutosize.State)
|
||||||
// testContainer.Children.FindAll(c => c.HasAutosizeChildren).ForEach(c => c.AutoSizeDebug = true);
|
// testContainer.Children.FindAll(c => c.HasAutosizeChildren).ForEach(c => c.AutoSizeDebug = true);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCornerMarkers(Container box, int size = 50, Color4? colour = null)
|
private void addCornerMarkers(Container box, int size = 50, Color4? colour = null)
|
||||||
{
|
{
|
||||||
box.Add(new DraggableTriangle
|
box.Add(new DraggableTriangle
|
||||||
{
|
{
|
||||||
//chameleon = true,
|
//chameleon = true,
|
||||||
Size = new Vector2(size, size),
|
Size = new Vector2(size, size),
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
AllowDrag = false,
|
AllowDrag = false,
|
||||||
Depth = -2,
|
Depth = -2,
|
||||||
Colour = colour ?? Color4.Red,
|
Colour = colour ?? Color4.Red,
|
||||||
});
|
});
|
||||||
|
|
||||||
box.Add(new DraggableTriangle
|
box.Add(new DraggableTriangle
|
||||||
{
|
{
|
||||||
//chameleon = true,
|
//chameleon = true,
|
||||||
Size = new Vector2(size, size),
|
Size = new Vector2(size, size),
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
AllowDrag = false,
|
AllowDrag = false,
|
||||||
Depth = -2,
|
Depth = -2,
|
||||||
Colour = colour ?? Color4.Red,
|
Colour = colour ?? Color4.Red,
|
||||||
});
|
});
|
||||||
|
|
||||||
box.Add(new DraggableTriangle
|
box.Add(new DraggableTriangle
|
||||||
{
|
{
|
||||||
//chameleon = true,
|
//chameleon = true,
|
||||||
Size = new Vector2(size, size),
|
Size = new Vector2(size, size),
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
AllowDrag = false,
|
AllowDrag = false,
|
||||||
Depth = -2,
|
Depth = -2,
|
||||||
Colour = colour ?? Color4.Red,
|
Colour = colour ?? Color4.Red,
|
||||||
});
|
});
|
||||||
|
|
||||||
box.Add(new DraggableTriangle
|
box.Add(new DraggableTriangle
|
||||||
{
|
{
|
||||||
//chameleon = true,
|
//chameleon = true,
|
||||||
Size = new Vector2(size, size),
|
Size = new Vector2(size, size),
|
||||||
Origin = Anchor.BottomRight,
|
Origin = Anchor.BottomRight,
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
AllowDrag = false,
|
AllowDrag = false,
|
||||||
Depth = -2,
|
Depth = -2,
|
||||||
Colour = colour ?? Color4.Red,
|
Colour = colour ?? Color4.Red,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DraggableTriangle : Triangle
|
internal class DraggableTriangle : Triangle
|
||||||
{
|
{
|
||||||
public bool AllowDrag = true;
|
public bool AllowDrag = true;
|
||||||
|
|
||||||
protected override bool OnDrag(InputState state)
|
protected override bool OnDrag(InputState state)
|
||||||
{
|
{
|
||||||
if (!AllowDrag) return false;
|
if (!AllowDrag) return false;
|
||||||
|
|
||||||
Position += state.Mouse.Delta;
|
Position += state.Mouse.Delta;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragEnd(InputState state)
|
protected override bool OnDragEnd(InputState state)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnDragStart(InputState state) => AllowDrag;
|
protected override bool OnDragStart(InputState state) => AllowDrag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,90 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Audio;
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Tests.Visual
|
namespace osu.Framework.Tests.Visual
|
||||||
{
|
{
|
||||||
public class TestCaseWaveform : FrameworkTestCase
|
public class TestCaseWaveform : FrameworkTestCase
|
||||||
{
|
{
|
||||||
private readonly List<WaveformGraph> waveforms = new List<WaveformGraph>();
|
private readonly List<WaveformGraph> waveforms = new List<WaveformGraph>();
|
||||||
|
|
||||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
{
|
{
|
||||||
typeof(Waveform),
|
typeof(Waveform),
|
||||||
typeof(WaveformGraph),
|
typeof(WaveformGraph),
|
||||||
typeof(DataStreamFileProcedures)
|
typeof(DataStreamFileProcedures)
|
||||||
};
|
};
|
||||||
|
|
||||||
public TestCaseWaveform()
|
public TestCaseWaveform()
|
||||||
{
|
{
|
||||||
FillFlowContainer flow;
|
FillFlowContainer flow;
|
||||||
Add(flow = new FillFlowContainer
|
Add(flow = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 10)
|
Spacing = new Vector2(0, 10)
|
||||||
});
|
});
|
||||||
|
|
||||||
for (int i = 1; i <= 16; i *= 2)
|
for (int i = 1; i <= 16; i *= 2)
|
||||||
{
|
{
|
||||||
var newDisplay = new WaveformGraph
|
var newDisplay = new WaveformGraph
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Resolution = 1f / i
|
Resolution = 1f / i
|
||||||
};
|
};
|
||||||
|
|
||||||
waveforms.Add(newDisplay);
|
waveforms.Add(newDisplay);
|
||||||
|
|
||||||
flow.Add(new Container
|
flow.Add(new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 100,
|
Height = 100,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
newDisplay,
|
newDisplay,
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Alpha = 0.75f
|
Alpha = 0.75f
|
||||||
},
|
},
|
||||||
new SpriteText
|
new SpriteText
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Padding = new MarginPadding(4),
|
Padding = new MarginPadding(4),
|
||||||
Text = $"Resolution: {1f / i:0.00}"
|
Text = $"Resolution: {1f / i:0.00}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(Game game)
|
private void load(Game game)
|
||||||
{
|
{
|
||||||
var waveform = new Waveform(game.Resources.GetStream("Tracks/sample-track.mp3"));
|
var waveform = new Waveform(game.Resources.GetStream("Tracks/sample-track.mp3"));
|
||||||
waveforms.ForEach(w => w.Waveform = waveform);
|
waveforms.ForEach(w => w.Waveform = waveform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
|
||||||
namespace osu.Framework.Tests
|
namespace osu.Framework.Tests
|
||||||
{
|
{
|
||||||
internal class VisualTestGame : TestGame
|
internal class VisualTestGame : TestGame
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Child = new DrawSizePreservingFillContainer
|
Child = new DrawSizePreservingFillContainer
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TestBrowser(),
|
new TestBrowser(),
|
||||||
new CursorContainer(),
|
new CursorContainer(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetHost(GameHost host)
|
public override void SetHost(GameHost host)
|
||||||
{
|
{
|
||||||
base.SetHost(host);
|
base.SetHost(host);
|
||||||
host.Window.CursorState |= CursorState.Hidden;
|
host.Window.CursorState |= CursorState.Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks a method as the loader-Method of a <see cref="osu.Framework.Graphics.Drawable"/>, allowing for automatic injection of dependencies via the parameters of the method.
|
/// Marks a method as the loader-Method of a <see cref="osu.Framework.Graphics.Drawable"/>, allowing for automatic injection of dependencies via the parameters of the method.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public class BackgroundDependencyLoader : Attribute
|
public class BackgroundDependencyLoader : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if nulls are allowed to be passed to the method marked with this attribute.
|
/// True if nulls are allowed to be passed to the method marked with this attribute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PermitNulls { get; private set; }
|
public bool PermitNulls { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks this method as the initializer for a class in the context of dependency injection.
|
/// Marks this method as the initializer for a class in the context of dependency injection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="permitNulls">If true, the initializer may be passed null for the dependencies we can't fulfill.</param>
|
/// <param name="permitNulls">If true, the initializer may be passed null for the dependencies we can't fulfill.</param>
|
||||||
public BackgroundDependencyLoader(bool permitNulls = false)
|
public BackgroundDependencyLoader(bool permitNulls = false)
|
||||||
{
|
{
|
||||||
PermitNulls = permitNulls;
|
PermitNulls = permitNulls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,76 +1,76 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A stack of buffers (arrays with elements of type <see cref="T"/>) which allows bypassing the
|
/// A stack of buffers (arrays with elements of type <see cref="T"/>) which allows bypassing the
|
||||||
/// garbage collector and expensive allocations when buffers can be frequently re-used.
|
/// garbage collector and expensive allocations when buffers can be frequently re-used.
|
||||||
/// The stack nature ensures that the most recently used buffers remain hot in memory, while
|
/// The stack nature ensures that the most recently used buffers remain hot in memory, while
|
||||||
/// at the same time guaranteeing a certain degree of order preservation.
|
/// at the same time guaranteeing a certain degree of order preservation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BufferStack<T>
|
public class BufferStack<T>
|
||||||
{
|
{
|
||||||
private readonly int maxAmountBuffers;
|
private readonly int maxAmountBuffers;
|
||||||
private readonly Stack<T[]> freeDataBuffers = new Stack<T[]>();
|
private readonly Stack<T[]> freeDataBuffers = new Stack<T[]>();
|
||||||
private readonly HashSet<T[]> usedDataBuffers = new HashSet<T[]>();
|
private readonly HashSet<T[]> usedDataBuffers = new HashSet<T[]>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new buffer stack containing a given maximum amount of buffers.
|
/// Creates a new buffer stack containing a given maximum amount of buffers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="maxAmountBuffers">The maximum amount of buffers to be contained within the buffer stack.</param>
|
/// <param name="maxAmountBuffers">The maximum amount of buffers to be contained within the buffer stack.</param>
|
||||||
public BufferStack(int maxAmountBuffers)
|
public BufferStack(int maxAmountBuffers)
|
||||||
{
|
{
|
||||||
this.maxAmountBuffers = maxAmountBuffers;
|
this.maxAmountBuffers = maxAmountBuffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T[] findFreeBuffer(int minimumLength)
|
private T[] findFreeBuffer(int minimumLength)
|
||||||
{
|
{
|
||||||
T[] buffer = null;
|
T[] buffer = null;
|
||||||
|
|
||||||
if (freeDataBuffers.Count > 0)
|
if (freeDataBuffers.Count > 0)
|
||||||
buffer = freeDataBuffers.Pop();
|
buffer = freeDataBuffers.Pop();
|
||||||
|
|
||||||
if (buffer == null || buffer.Length < minimumLength)
|
if (buffer == null || buffer.Length < minimumLength)
|
||||||
buffer = new T[minimumLength];
|
buffer = new T[minimumLength];
|
||||||
|
|
||||||
if (usedDataBuffers.Count < maxAmountBuffers)
|
if (usedDataBuffers.Count < maxAmountBuffers)
|
||||||
usedDataBuffers.Add(buffer);
|
usedDataBuffers.Add(buffer);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void returnFreeBuffer(T[] buffer)
|
private void returnFreeBuffer(T[] buffer)
|
||||||
{
|
{
|
||||||
if (usedDataBuffers.Remove(buffer))
|
if (usedDataBuffers.Remove(buffer))
|
||||||
// We are here if the element was successfully found and removed
|
// We are here if the element was successfully found and removed
|
||||||
freeDataBuffers.Push(buffer);
|
freeDataBuffers.Push(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reserve a buffer from the buffer stack. If no free buffers are available, a new one is allocated.
|
/// Reserve a buffer from the buffer stack. If no free buffers are available, a new one is allocated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="minimumLength">The minimum length required of the reserved buffer.</param>
|
/// <param name="minimumLength">The minimum length required of the reserved buffer.</param>
|
||||||
/// <returns>The reserved buffer.</returns>
|
/// <returns>The reserved buffer.</returns>
|
||||||
public T[] ReserveBuffer(int minimumLength)
|
public T[] ReserveBuffer(int minimumLength)
|
||||||
{
|
{
|
||||||
T[] buffer;
|
T[] buffer;
|
||||||
lock (freeDataBuffers)
|
lock (freeDataBuffers)
|
||||||
buffer = findFreeBuffer(minimumLength);
|
buffer = findFreeBuffer(minimumLength);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Frees a previously reserved buffer for future reservations.
|
/// Frees a previously reserved buffer for future reservations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buffer">The buffer to be freed. If the buffer has not previously been reserved then this method does nothing.</param>
|
/// <param name="buffer">The buffer to be freed. If the buffer has not previously been reserved then this method does nothing.</param>
|
||||||
public void FreeBuffer(T[] buffer)
|
public void FreeBuffer(T[] buffer)
|
||||||
{
|
{
|
||||||
lock (freeDataBuffers)
|
lock (freeDataBuffers)
|
||||||
returnFreeBuffer(buffer);
|
returnFreeBuffer(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,196 +1,196 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using osu.Framework.Extensions.ExceptionExtensions;
|
using osu.Framework.Extensions.ExceptionExtensions;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hierarchically caches dependencies and can inject those automatically into types registered for dependency injection.
|
/// Hierarchically caches dependencies and can inject those automatically into types registered for dependency injection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DependencyContainer : IReadOnlyDependencyContainer
|
public class DependencyContainer : IReadOnlyDependencyContainer
|
||||||
{
|
{
|
||||||
private delegate object ObjectActivator(DependencyContainer dc, object instance);
|
private delegate object ObjectActivator(DependencyContainer dc, object instance);
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Type, ObjectActivator> activators = new ConcurrentDictionary<Type, ObjectActivator>();
|
private readonly ConcurrentDictionary<Type, ObjectActivator> activators = new ConcurrentDictionary<Type, ObjectActivator>();
|
||||||
private readonly ConcurrentDictionary<Type, object> cache = new ConcurrentDictionary<Type, object>();
|
private readonly ConcurrentDictionary<Type, object> cache = new ConcurrentDictionary<Type, object>();
|
||||||
|
|
||||||
private readonly IReadOnlyDependencyContainer parentContainer;
|
private readonly IReadOnlyDependencyContainer parentContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new DependencyContainer instance.
|
/// Create a new DependencyContainer instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parent">An optional parent container which we should use as a fallback for cache lookups.</param>
|
/// <param name="parent">An optional parent container which we should use as a fallback for cache lookups.</param>
|
||||||
public DependencyContainer(IReadOnlyDependencyContainer parent = null)
|
public DependencyContainer(IReadOnlyDependencyContainer parent = null)
|
||||||
{
|
{
|
||||||
parentContainer = parent;
|
parentContainer = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodInfo getLoaderMethod(Type type)
|
private MethodInfo getLoaderMethod(Type type)
|
||||||
{
|
{
|
||||||
var loaderMethods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(
|
var loaderMethods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(
|
||||||
mi => mi.GetCustomAttribute<BackgroundDependencyLoader>() != null).ToArray();
|
mi => mi.GetCustomAttribute<BackgroundDependencyLoader>() != null).ToArray();
|
||||||
if (loaderMethods.Length == 0)
|
if (loaderMethods.Length == 0)
|
||||||
return null;
|
return null;
|
||||||
if (loaderMethods.Length == 1)
|
if (loaderMethods.Length == 1)
|
||||||
return loaderMethods[0];
|
return loaderMethods[0];
|
||||||
throw new InvalidOperationException($"The type {type.ReadableName()} has more than one method marked with the {nameof(BackgroundDependencyLoader)}-Attribute. Any given type can only have one such method.");
|
throw new InvalidOperationException($"The type {type.ReadableName()} has more than one method marked with the {nameof(BackgroundDependencyLoader)}-Attribute. Any given type can only have one such method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(Type type, bool lazy)
|
private void register(Type type, bool lazy)
|
||||||
{
|
{
|
||||||
if (activators.ContainsKey(type))
|
if (activators.ContainsKey(type))
|
||||||
throw new InvalidOperationException($@"Type {type.FullName} can not be registered twice");
|
throw new InvalidOperationException($@"Type {type.FullName} can not be registered twice");
|
||||||
|
|
||||||
var initialize = getLoaderMethod(type);
|
var initialize = getLoaderMethod(type);
|
||||||
var constructor = type.GetConstructor(new Type[] { });
|
var constructor = type.GetConstructor(new Type[] { });
|
||||||
|
|
||||||
var initializerMethods = new List<MethodInfo>();
|
var initializerMethods = new List<MethodInfo>();
|
||||||
|
|
||||||
for (Type parent = type.BaseType; parent != typeof(object); parent = parent?.BaseType)
|
for (Type parent = type.BaseType; parent != typeof(object); parent = parent?.BaseType)
|
||||||
{
|
{
|
||||||
var init = getLoaderMethod(parent);
|
var init = getLoaderMethod(parent);
|
||||||
if (init != null)
|
if (init != null)
|
||||||
initializerMethods.Insert(0, init);
|
initializerMethods.Insert(0, init);
|
||||||
}
|
}
|
||||||
if (initialize != null)
|
if (initialize != null)
|
||||||
initializerMethods.Add(initialize);
|
initializerMethods.Add(initialize);
|
||||||
|
|
||||||
var initializers = initializerMethods.Select(initializer =>
|
var initializers = initializerMethods.Select(initializer =>
|
||||||
{
|
{
|
||||||
var permitNull = initializer.GetCustomAttribute<BackgroundDependencyLoader>().PermitNulls;
|
var permitNull = initializer.GetCustomAttribute<BackgroundDependencyLoader>().PermitNulls;
|
||||||
var parameters = initializer.GetParameters().Select(p => p.ParameterType)
|
var parameters = initializer.GetParameters().Select(p => p.ParameterType)
|
||||||
.Select(t => new Func<object>(() =>
|
.Select(t => new Func<object>(() =>
|
||||||
{
|
{
|
||||||
var val = Get(t);
|
var val = Get(t);
|
||||||
if (val == null && !permitNull)
|
if (val == null && !permitNull)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$@"Type {t.FullName} is not registered, and is a dependency of {type.FullName}");
|
$@"Type {t.FullName} is not registered, and is a dependency of {type.FullName}");
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
})).ToList();
|
})).ToList();
|
||||||
// Test that we already have all the dependencies registered
|
// Test that we already have all the dependencies registered
|
||||||
if (!lazy)
|
if (!lazy)
|
||||||
parameters.ForEach(p => p());
|
parameters.ForEach(p => p());
|
||||||
return new Action<object>(instance =>
|
return new Action<object>(instance =>
|
||||||
{
|
{
|
||||||
var p = parameters.Select(pa => pa()).ToArray();
|
var p = parameters.Select(pa => pa()).ToArray();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
initializer.Invoke(instance, p);
|
initializer.Invoke(instance, p);
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException e)
|
catch (TargetInvocationException e)
|
||||||
{
|
{
|
||||||
new RecursiveLoadException(e.GetLastInvocation(), initializer).Rethrow();
|
new RecursiveLoadException(e.GetLastInvocation(), initializer).Rethrow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
activators[type] = (container, instance) =>
|
activators[type] = (container, instance) =>
|
||||||
{
|
{
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
{
|
{
|
||||||
if (constructor == null)
|
if (constructor == null)
|
||||||
throw new InvalidOperationException($@"Type {type.FullName} must have a parameterless constructor to initialize one from scratch.");
|
throw new InvalidOperationException($@"Type {type.FullName} must have a parameterless constructor to initialize one from scratch.");
|
||||||
instance = Activator.CreateInstance(type);
|
instance = Activator.CreateInstance(type);
|
||||||
}
|
}
|
||||||
initializers.ForEach(init => init(instance));
|
initializers.ForEach(init => init(instance));
|
||||||
return instance;
|
return instance;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a type and configures a default allocator for it that injects its
|
/// Registers a type and configures a default allocator for it that injects its
|
||||||
/// dependencies.
|
/// dependencies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Register<T>(bool lazy = false) where T : class => register(typeof(T), lazy);
|
public void Register<T>(bool lazy = false) where T : class => register(typeof(T), lazy);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a type that allocates with a custom allocator.
|
/// Registers a type that allocates with a custom allocator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Register<T>(Func<DependencyContainer, T> activator) where T : class
|
public void Register<T>(Func<DependencyContainer, T> activator) where T : class
|
||||||
{
|
{
|
||||||
var type = typeof(T);
|
var type = typeof(T);
|
||||||
if (activators.ContainsKey(type))
|
if (activators.ContainsKey(type))
|
||||||
throw new InvalidOperationException($@"Type {typeof(T).FullName} is already registered");
|
throw new InvalidOperationException($@"Type {typeof(T).FullName} is already registered");
|
||||||
activators[type] = (d, i) => i ?? activator(d);
|
activators[type] = (d, i) => i ?? activator(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Caches an instance of a type as its most derived type. This instance will be returned each time you <see cref="Get(Type)"/>.
|
/// Caches an instance of a type as its most derived type. This instance will be returned each time you <see cref="Get(Type)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">The instance to cache.</param>
|
/// <param name="instance">The instance to cache.</param>
|
||||||
public void Cache<T>(T instance)
|
public void Cache<T>(T instance)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
if (instance == null) throw new ArgumentNullException(nameof(instance));
|
if (instance == null) throw new ArgumentNullException(nameof(instance));
|
||||||
|
|
||||||
cache[instance.GetType()] = instance;
|
cache[instance.GetType()] = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Caches an instance of a type as a type of <typeparamref name="T"/>. This instance will be returned each time you <see cref="Get(Type)"/>.
|
/// Caches an instance of a type as a type of <typeparamref name="T"/>. This instance will be returned each time you <see cref="Get(Type)"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">The instance to cache. Must be or derive from <typeparamref name="T"/>.</param>
|
/// <param name="instance">The instance to cache. Must be or derive from <typeparamref name="T"/>.</param>
|
||||||
public void CacheAs<T>(T instance)
|
public void CacheAs<T>(T instance)
|
||||||
where T : class
|
where T : class
|
||||||
{
|
{
|
||||||
cache[typeof(T)] = instance ?? throw new ArgumentNullException(nameof(instance));
|
cache[typeof(T)] = instance ?? throw new ArgumentNullException(nameof(instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a cached dependency of <paramref name="type"/> if it exists. If not, then the parent
|
/// Retrieves a cached dependency of <paramref name="type"/> if it exists. If not, then the parent
|
||||||
/// <see cref="IReadOnlyDependencyContainer"/> is recursively queried. If no parent contains
|
/// <see cref="IReadOnlyDependencyContainer"/> is recursively queried. If no parent contains
|
||||||
/// <paramref name="type"/>, then null is returned.
|
/// <paramref name="type"/>, then null is returned.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The dependency type to query for.</param>
|
/// <param name="type">The dependency type to query for.</param>
|
||||||
/// <returns>The requested dependency, or null if not found.</returns>
|
/// <returns>The requested dependency, or null if not found.</returns>
|
||||||
public object Get(Type type)
|
public object Get(Type type)
|
||||||
{
|
{
|
||||||
if (cache.TryGetValue(type, out object ret))
|
if (cache.TryGetValue(type, out object ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return parentContainer?.Get(type);
|
return parentContainer?.Get(type);
|
||||||
|
|
||||||
//we don't ever want to instantiate for now, as this breaks expectations when using permitNull.
|
//we don't ever want to instantiate for now, as this breaks expectations when using permitNull.
|
||||||
//need to revisit this when/if it is required.
|
//need to revisit this when/if it is required.
|
||||||
//if (!activators.ContainsKey(type))
|
//if (!activators.ContainsKey(type))
|
||||||
// return null; // Or an exception?
|
// return null; // Or an exception?
|
||||||
//object instance = activators[type](this, null);
|
//object instance = activators[type](this, null);
|
||||||
//if (cacheable.Contains(type))
|
//if (cacheable.Contains(type))
|
||||||
// cache[type] = instance;
|
// cache[type] = instance;
|
||||||
//return instance;
|
//return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Injects dependencies into the given instance.
|
/// Injects dependencies into the given instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the instance to inject dependencies into.</typeparam>
|
/// <typeparam name="T">The type of the instance to inject dependencies into.</typeparam>
|
||||||
/// <param name="instance">The instance to inject dependencies into.</param>
|
/// <param name="instance">The instance to inject dependencies into.</param>
|
||||||
/// <param name="autoRegister">True if the instance should be automatically registered as injectable if it isn't already.</param>
|
/// <param name="autoRegister">True if the instance should be automatically registered as injectable if it isn't already.</param>
|
||||||
/// <param name="lazy">True if the dependencies should be initialized lazily.</param>
|
/// <param name="lazy">True if the dependencies should be initialized lazily.</param>
|
||||||
public void Inject<T>(T instance, bool autoRegister = true, bool lazy = false) where T : class
|
public void Inject<T>(T instance, bool autoRegister = true, bool lazy = false) where T : class
|
||||||
{
|
{
|
||||||
var type = instance.GetType();
|
var type = instance.GetType();
|
||||||
|
|
||||||
// TODO: consider using parentContainer for activator lookups as a potential performance improvement.
|
// TODO: consider using parentContainer for activator lookups as a potential performance improvement.
|
||||||
|
|
||||||
lock (activators)
|
lock (activators)
|
||||||
if (autoRegister && !activators.ContainsKey(type))
|
if (autoRegister && !activators.ContainsKey(type))
|
||||||
register(type, lazy);
|
register(type, lazy);
|
||||||
|
|
||||||
if (!activators.TryGetValue(type, out ObjectActivator activator))
|
if (!activators.TryGetValue(type, out ObjectActivator activator))
|
||||||
throw new InvalidOperationException("DI Initialisation failed badly.");
|
throw new InvalidOperationException("DI Initialisation failed badly.");
|
||||||
|
|
||||||
activator(this, instance);
|
activator(this, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,42 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read-only interface into a dependency container capable of injective and retrieving dependencies based
|
/// Read-only interface into a dependency container capable of injective and retrieving dependencies based
|
||||||
/// on types.
|
/// on types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IReadOnlyDependencyContainer
|
public interface IReadOnlyDependencyContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a cached dependency of <paramref name="type"/> if it exists and null otherwise.
|
/// Retrieves a cached dependency of <paramref name="type"/> if it exists and null otherwise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The dependency type to query for.</param>
|
/// <param name="type">The dependency type to query for.</param>
|
||||||
/// <returns>The requested dependency, or null if not found.</returns>
|
/// <returns>The requested dependency, or null if not found.</returns>
|
||||||
object Get(Type type);
|
object Get(Type type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Injects dependencies into the given instance.
|
/// Injects dependencies into the given instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of the instance to inject dependencies into.</typeparam>
|
/// <typeparam name="T">The type of the instance to inject dependencies into.</typeparam>
|
||||||
/// <param name="instance">The instance to inject dependencies into.</param>
|
/// <param name="instance">The instance to inject dependencies into.</param>
|
||||||
/// <param name="autoRegister">True if the instance should be automatically registered as injectable if it isn't already.</param>
|
/// <param name="autoRegister">True if the instance should be automatically registered as injectable if it isn't already.</param>
|
||||||
/// <param name="lazy">True if the dependencies should be initialized lazily.</param>
|
/// <param name="lazy">True if the dependencies should be initialized lazily.</param>
|
||||||
void Inject<T>(T instance, bool autoRegister = true, bool lazy = false) where T : class;
|
void Inject<T>(T instance, bool autoRegister = true, bool lazy = false) where T : class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReadOnlyDependencyContainerExtensions
|
public static class ReadOnlyDependencyContainerExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a cached dependency of type <typeparamref name="T"/> if it exists and null otherwise.
|
/// Retrieves a cached dependency of type <typeparamref name="T"/> if it exists and null otherwise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The dependency type to query for.</typeparam>
|
/// <typeparam name="T">The dependency type to query for.</typeparam>
|
||||||
/// <param name="container">The <see cref="IReadOnlyDependencyContainer"/> to query.</param>
|
/// <param name="container">The <see cref="IReadOnlyDependencyContainer"/> to query.</param>
|
||||||
/// <returns>The requested dependency, or null if not found.</returns>
|
/// <returns>The requested dependency, or null if not found.</returns>
|
||||||
public static T Get<T>(this IReadOnlyDependencyContainer container) where T : class =>
|
public static T Get<T>(this IReadOnlyDependencyContainer container) where T : class =>
|
||||||
(T)container.Get(typeof(T));
|
(T)container.Get(typeof(T));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instances of this class capture an action for later cleanup. When a method returns an instance of this class, the appropriate usage is:
|
/// Instances of this class capture an action for later cleanup. When a method returns an instance of this class, the appropriate usage is:
|
||||||
/// <code>using (SomeMethod())
|
/// <code>using (SomeMethod())
|
||||||
/// {
|
/// {
|
||||||
/// // ...
|
/// // ...
|
||||||
/// }</code>
|
/// }</code>
|
||||||
/// The using block will automatically dispose the returned instance, doing the necessary cleanup work.
|
/// The using block will automatically dispose the returned instance, doing the necessary cleanup work.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InvokeOnDisposal : IDisposable
|
public class InvokeOnDisposal : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Action action;
|
private readonly Action action;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance, capturing the given action to be run during disposal.
|
/// Constructs a new instance, capturing the given action to be run during disposal.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="action">The action to invoke during disposal.</param>
|
/// <param name="action">The action to invoke during disposal.</param>
|
||||||
public InvokeOnDisposal(Action action) => this.action = action ?? throw new ArgumentNullException(nameof(action));
|
public InvokeOnDisposal(Action action) => this.action = action ?? throw new ArgumentNullException(nameof(action));
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes this instance, calling the initially captured action.
|
/// Disposes this instance, calling the initially captured action.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
//no isDisposed check here so we can reuse these instances multiple times to save on allocations.
|
//no isDisposed check here so we can reuse these instances multiple times to save on allocations.
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,59 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
public class ObjectStack<T> where T : new()
|
public class ObjectStack<T> where T : new()
|
||||||
{
|
{
|
||||||
private readonly int maxAmountObjects;
|
private readonly int maxAmountObjects;
|
||||||
private readonly Stack<T> freeObjects = new Stack<T>();
|
private readonly Stack<T> freeObjects = new Stack<T>();
|
||||||
private int usedObjects;
|
private int usedObjects;
|
||||||
|
|
||||||
public ObjectStack(int maxAmountObjects = -1)
|
public ObjectStack(int maxAmountObjects = -1)
|
||||||
{
|
{
|
||||||
this.maxAmountObjects = maxAmountObjects;
|
this.maxAmountObjects = maxAmountObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
private T findFreeObject()
|
private T findFreeObject()
|
||||||
{
|
{
|
||||||
T o = freeObjects.Count > 0 ? freeObjects.Pop() : new T();
|
T o = freeObjects.Count > 0 ? freeObjects.Pop() : new T();
|
||||||
|
|
||||||
if (maxAmountObjects == -1 || usedObjects < maxAmountObjects)
|
if (maxAmountObjects == -1 || usedObjects < maxAmountObjects)
|
||||||
usedObjects++;
|
usedObjects++;
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void returnFreeObject(T o)
|
private void returnFreeObject(T o)
|
||||||
{
|
{
|
||||||
if (usedObjects-- > 0)
|
if (usedObjects-- > 0)
|
||||||
// We are here if the element was successfully found and removed
|
// We are here if the element was successfully found and removed
|
||||||
freeObjects.Push(o);
|
freeObjects.Push(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reserve an object from the pool. This is used to avoid excessive amounts of heap allocations.
|
/// Reserve an object from the pool. This is used to avoid excessive amounts of heap allocations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The reserved object.</returns>
|
/// <returns>The reserved object.</returns>
|
||||||
public T ReserveObject()
|
public T ReserveObject()
|
||||||
{
|
{
|
||||||
T o;
|
T o;
|
||||||
lock (freeObjects)
|
lock (freeObjects)
|
||||||
o = findFreeObject();
|
o = findFreeObject();
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Frees a previously reserved object for future reservations.
|
/// Frees a previously reserved object for future reservations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="o">The object to be freed. If the object has not previously been reserved then this method does nothing.</param>
|
/// <param name="o">The object to be freed. If the object has not previously been reserved then this method does nothing.</param>
|
||||||
public void FreeObject(T o)
|
public void FreeObject(T o)
|
||||||
{
|
{
|
||||||
lock (freeObjects)
|
lock (freeObjects)
|
||||||
returnFreeObject(o);
|
returnFreeObject(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
public class ObjectUsage<T> : IDisposable
|
public class ObjectUsage<T> : IDisposable
|
||||||
{
|
{
|
||||||
public T Object;
|
public T Object;
|
||||||
public int Index;
|
public int Index;
|
||||||
|
|
||||||
public long FrameId;
|
public long FrameId;
|
||||||
|
|
||||||
internal Action<ObjectUsage<T>, UsageType> Finish;
|
internal Action<ObjectUsage<T>, UsageType> Finish;
|
||||||
|
|
||||||
public UsageType Usage;
|
public UsageType Usage;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Finish?.Invoke(this, Usage);
|
Finish?.Invoke(this, Usage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum UsageType
|
public enum UsageType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Read,
|
Read,
|
||||||
Write
|
Write
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The exception that is re-thrown by <see cref="DependencyContainer"/> when a loader invocation fails.
|
/// The exception that is re-thrown by <see cref="DependencyContainer"/> when a loader invocation fails.
|
||||||
/// This exception type builds a readablestacktrace message since loader invocations tend to be long recursive reflection calls.
|
/// This exception type builds a readablestacktrace message since loader invocations tend to be long recursive reflection calls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RecursiveLoadException : Exception
|
public class RecursiveLoadException : Exception
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Types that are ignored for the custom stack traces. The initializers for these typically invoke
|
/// Types that are ignored for the custom stack traces. The initializers for these typically invoke
|
||||||
/// initializers in user code where the problem actually lies.
|
/// initializers in user code where the problem actually lies.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly Type[] blacklist =
|
private static readonly Type[] blacklist =
|
||||||
{
|
{
|
||||||
typeof(Container),
|
typeof(Container),
|
||||||
typeof(Container<>),
|
typeof(Container<>),
|
||||||
typeof(CompositeDrawable)
|
typeof(CompositeDrawable)
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly StringBuilder traceBuilder;
|
private readonly StringBuilder traceBuilder;
|
||||||
private readonly Exception original;
|
private readonly Exception original;
|
||||||
|
|
||||||
public RecursiveLoadException(Exception original, MethodInfo loaderMethod)
|
public RecursiveLoadException(Exception original, MethodInfo loaderMethod)
|
||||||
{
|
{
|
||||||
var recursive = original as RecursiveLoadException;
|
var recursive = original as RecursiveLoadException;
|
||||||
|
|
||||||
this.original = recursive?.original ?? original;
|
this.original = recursive?.original ?? original;
|
||||||
traceBuilder = recursive?.traceBuilder ?? new StringBuilder();
|
traceBuilder = recursive?.traceBuilder ?? new StringBuilder();
|
||||||
|
|
||||||
// Find the location of the load method
|
// Find the location of the load method
|
||||||
var loaderLocation = $"{loaderMethod.DeclaringType}.{loaderMethod.Name}";
|
var loaderLocation = $"{loaderMethod.DeclaringType}.{loaderMethod.Name}";
|
||||||
|
|
||||||
if (recursive == null)
|
if (recursive == null)
|
||||||
{
|
{
|
||||||
var lines = original.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
var lines = original.StackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
// Write all lines from the original exception until the loader method is hit
|
// Write all lines from the original exception until the loader method is hit
|
||||||
foreach (var o in lines)
|
foreach (var o in lines)
|
||||||
{
|
{
|
||||||
traceBuilder.AppendLine(o);
|
traceBuilder.AppendLine(o);
|
||||||
if (o.Contains(loaderLocation))
|
if (o.Contains(loaderLocation))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!blacklist.Contains(loaderMethod.DeclaringType))
|
else if (!blacklist.Contains(loaderMethod.DeclaringType))
|
||||||
traceBuilder.AppendLine($" at {loaderLocation} ()");
|
traceBuilder.AppendLine($" at {loaderLocation} ()");
|
||||||
|
|
||||||
stackTrace = traceBuilder.ToString();
|
stackTrace = traceBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Message => original.Message;
|
public override string Message => original.Message;
|
||||||
|
|
||||||
private readonly string stackTrace;
|
private readonly string stackTrace;
|
||||||
public override string StackTrace => stackTrace;
|
public override string StackTrace => stackTrace;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
builder.AppendLine($"{original.GetType()}: {original.Message}");
|
builder.AppendLine($"{original.GetType()}: {original.Message}");
|
||||||
builder.AppendLine(stackTrace);
|
builder.AppendLine(stackTrace);
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +1,115 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A key-value store which supports cleaning up items after a specified expiry time.
|
/// A key-value store which supports cleaning up items after a specified expiry time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TimedExpiryCache<TKey, TValue> : IDisposable
|
public class TimedExpiryCache<TKey, TValue> : IDisposable
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<TKey, TimedObject<TValue>> dictionary = new ConcurrentDictionary<TKey, TimedObject<TValue>>();
|
private readonly ConcurrentDictionary<TKey, TimedObject<TValue>> dictionary = new ConcurrentDictionary<TKey, TimedObject<TValue>>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Time in milliseconds after last access after which items will be cleaned up.
|
/// Time in milliseconds after last access after which items will be cleaned up.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ExpiryTime = 5000;
|
public int ExpiryTime = 5000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The interval in milliseconds between checks for expiry.
|
/// The interval in milliseconds between checks for expiry.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int CheckPeriod = 5000;
|
public readonly int CheckPeriod = 5000;
|
||||||
|
|
||||||
private readonly Timer timer;
|
private readonly Timer timer;
|
||||||
|
|
||||||
public TimedExpiryCache()
|
public TimedExpiryCache()
|
||||||
{
|
{
|
||||||
timer = new Timer(checkExpiry, null, 0, CheckPeriod);
|
timer = new Timer(checkExpiry, null, 0, CheckPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Add(TKey key, TValue value)
|
internal void Add(TKey key, TValue value)
|
||||||
{
|
{
|
||||||
dictionary.TryAdd(key, new TimedObject<TValue>(value));
|
dictionary.TryAdd(key, new TimedObject<TValue>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkExpiry(object state)
|
private void checkExpiry(object state)
|
||||||
{
|
{
|
||||||
var now = DateTimeOffset.Now;
|
var now = DateTimeOffset.Now;
|
||||||
|
|
||||||
foreach (var v in dictionary)
|
foreach (var v in dictionary)
|
||||||
{
|
{
|
||||||
if ((now - v.Value.LastAccessTime).TotalMilliseconds > ExpiryTime)
|
if ((now - v.Value.LastAccessTime).TotalMilliseconds > ExpiryTime)
|
||||||
dictionary.TryRemove(v.Key, out _);
|
dictionary.TryRemove(v.Key, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetValue(TKey key, out TValue value)
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
{
|
{
|
||||||
if (!dictionary.TryGetValue(key, out TimedObject<TValue> timed))
|
if (!dictionary.TryGetValue(key, out TimedObject<TValue> timed))
|
||||||
{
|
{
|
||||||
value = default(TValue);
|
value = default(TValue);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = timed.Value;
|
value = timed.Value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!isDisposed)
|
if (!isDisposed)
|
||||||
{
|
{
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
timer.Dispose();
|
timer.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~TimedExpiryCache()
|
~TimedExpiryCache()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private class TimedObject<T>
|
private class TimedObject<T>
|
||||||
{
|
{
|
||||||
public DateTimeOffset LastAccessTime;
|
public DateTimeOffset LastAccessTime;
|
||||||
|
|
||||||
private readonly T value;
|
private readonly T value;
|
||||||
|
|
||||||
public T Value
|
public T Value
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
updateAccessTime();
|
updateAccessTime();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimedObject(T value)
|
public TimedObject(T value)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
updateAccessTime();
|
updateAccessTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAccessTime()
|
private void updateAccessTime()
|
||||||
{
|
{
|
||||||
LastAccessTime = DateTimeOffset.Now;
|
LastAccessTime = DateTimeOffset.Now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,91 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace osu.Framework.Allocation
|
namespace osu.Framework.Allocation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles triple-buffering of any object type.
|
/// Handles triple-buffering of any object type.
|
||||||
/// Thread safety assumes at most one writer and one reader.
|
/// Thread safety assumes at most one writer and one reader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TripleBuffer<T>
|
public class TripleBuffer<T>
|
||||||
{
|
{
|
||||||
private readonly ObjectUsage<T>[] buffers = new ObjectUsage<T>[3];
|
private readonly ObjectUsage<T>[] buffers = new ObjectUsage<T>[3];
|
||||||
|
|
||||||
private int read;
|
private int read;
|
||||||
private int write;
|
private int write;
|
||||||
private int lastWrite = -1;
|
private int lastWrite = -1;
|
||||||
|
|
||||||
private long currentFrame;
|
private long currentFrame;
|
||||||
|
|
||||||
private readonly Action<ObjectUsage<T>, UsageType> finishDelegate;
|
private readonly Action<ObjectUsage<T>, UsageType> finishDelegate;
|
||||||
|
|
||||||
public TripleBuffer()
|
public TripleBuffer()
|
||||||
{
|
{
|
||||||
//caching the delegate means we only have to allocate it once, rather than once per created buffer.
|
//caching the delegate means we only have to allocate it once, rather than once per created buffer.
|
||||||
finishDelegate = finish;
|
finishDelegate = finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectUsage<T> Get(UsageType usage)
|
public ObjectUsage<T> Get(UsageType usage)
|
||||||
{
|
{
|
||||||
switch (usage)
|
switch (usage)
|
||||||
{
|
{
|
||||||
case UsageType.Write:
|
case UsageType.Write:
|
||||||
lock (buffers)
|
lock (buffers)
|
||||||
{
|
{
|
||||||
while (buffers[write]?.Usage == UsageType.Read || write == lastWrite)
|
while (buffers[write]?.Usage == UsageType.Read || write == lastWrite)
|
||||||
write = (write + 1) % 3;
|
write = (write + 1) % 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffers[write] == null)
|
if (buffers[write] == null)
|
||||||
{
|
{
|
||||||
buffers[write] = new ObjectUsage<T>
|
buffers[write] = new ObjectUsage<T>
|
||||||
{
|
{
|
||||||
Finish = finishDelegate,
|
Finish = finishDelegate,
|
||||||
Usage = UsageType.Write,
|
Usage = UsageType.Write,
|
||||||
Index = write,
|
Index = write,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffers[write].Usage = UsageType.Write;
|
buffers[write].Usage = UsageType.Write;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffers[write].FrameId = Interlocked.Increment(ref currentFrame);
|
buffers[write].FrameId = Interlocked.Increment(ref currentFrame);
|
||||||
return buffers[write];
|
return buffers[write];
|
||||||
case UsageType.Read:
|
case UsageType.Read:
|
||||||
if (lastWrite < 0) return null;
|
if (lastWrite < 0) return null;
|
||||||
|
|
||||||
lock (buffers)
|
lock (buffers)
|
||||||
{
|
{
|
||||||
read = lastWrite;
|
read = lastWrite;
|
||||||
buffers[read].Usage = UsageType.Read;
|
buffers[read].Usage = UsageType.Read;
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffers[read];
|
return buffers[read];
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finish(ObjectUsage<T> obj, UsageType type)
|
private void finish(ObjectUsage<T> obj, UsageType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case UsageType.Read:
|
case UsageType.Read:
|
||||||
lock (buffers)
|
lock (buffers)
|
||||||
buffers[read].Usage = UsageType.None;
|
buffers[read].Usage = UsageType.None;
|
||||||
break;
|
break;
|
||||||
case UsageType.Write:
|
case UsageType.Write:
|
||||||
lock (buffers)
|
lock (buffers)
|
||||||
{
|
{
|
||||||
buffers[write].Usage = UsageType.None;
|
buffers[write].Usage = UsageType.None;
|
||||||
lastWrite = write;
|
lastWrite = write;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,148 +1,148 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
public class AdjustableAudioComponent : AudioComponent
|
public class AdjustableAudioComponent : AudioComponent
|
||||||
{
|
{
|
||||||
private readonly HashSet<BindableDouble> volumeAdjustments = new HashSet<BindableDouble>();
|
private readonly HashSet<BindableDouble> volumeAdjustments = new HashSet<BindableDouble>();
|
||||||
private readonly HashSet<BindableDouble> balanceAdjustments = new HashSet<BindableDouble>();
|
private readonly HashSet<BindableDouble> balanceAdjustments = new HashSet<BindableDouble>();
|
||||||
private readonly HashSet<BindableDouble> frequencyAdjustments = new HashSet<BindableDouble>();
|
private readonly HashSet<BindableDouble> frequencyAdjustments = new HashSet<BindableDouble>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Global volume of this component.
|
/// Global volume of this component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble Volume = new BindableDouble(1)
|
public readonly BindableDouble Volume = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
protected readonly BindableDouble VolumeCalculated = new BindableDouble(1)
|
protected readonly BindableDouble VolumeCalculated = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Playback balance of this sample (-1 .. 1 where 0 is centered)
|
/// Playback balance of this sample (-1 .. 1 where 0 is centered)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble Balance = new BindableDouble
|
public readonly BindableDouble Balance = new BindableDouble
|
||||||
{
|
{
|
||||||
MinValue = -1,
|
MinValue = -1,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
protected readonly BindableDouble BalanceCalculated = new BindableDouble
|
protected readonly BindableDouble BalanceCalculated = new BindableDouble
|
||||||
{
|
{
|
||||||
MinValue = -1,
|
MinValue = -1,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency.
|
/// Rate at which the component is played back (affects pitch). 1 is 100% playback speed, or default frequency.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble Frequency = new BindableDouble(1);
|
public readonly BindableDouble Frequency = new BindableDouble(1);
|
||||||
|
|
||||||
protected readonly BindableDouble FrequencyCalculated = new BindableDouble(1);
|
protected readonly BindableDouble FrequencyCalculated = new BindableDouble(1);
|
||||||
|
|
||||||
protected AdjustableAudioComponent()
|
protected AdjustableAudioComponent()
|
||||||
{
|
{
|
||||||
Volume.ValueChanged += InvalidateState;
|
Volume.ValueChanged += InvalidateState;
|
||||||
Balance.ValueChanged += InvalidateState;
|
Balance.ValueChanged += InvalidateState;
|
||||||
Frequency.ValueChanged += InvalidateState;
|
Frequency.ValueChanged += InvalidateState;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InvalidateState(double newValue = 0)
|
internal void InvalidateState(double newValue = 0)
|
||||||
{
|
{
|
||||||
EnqueueAction(OnStateChanged);
|
EnqueueAction(OnStateChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal virtual void OnStateChanged()
|
internal virtual void OnStateChanged()
|
||||||
{
|
{
|
||||||
VolumeCalculated.Value = volumeAdjustments.Aggregate(Volume.Value, (current, adj) => current * adj);
|
VolumeCalculated.Value = volumeAdjustments.Aggregate(Volume.Value, (current, adj) => current * adj);
|
||||||
BalanceCalculated.Value = balanceAdjustments.Aggregate(Balance.Value, (current, adj) => current + adj);
|
BalanceCalculated.Value = balanceAdjustments.Aggregate(Balance.Value, (current, adj) => current + adj);
|
||||||
FrequencyCalculated.Value = frequencyAdjustments.Aggregate(Frequency.Value, (current, adj) => current * adj);
|
FrequencyCalculated.Value = frequencyAdjustments.Aggregate(Frequency.Value, (current, adj) => current * adj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAdjustmentDependency(AdjustableAudioComponent component)
|
public void AddAdjustmentDependency(AdjustableAudioComponent component)
|
||||||
{
|
{
|
||||||
AddAdjustment(AdjustableProperty.Balance, component.BalanceCalculated);
|
AddAdjustment(AdjustableProperty.Balance, component.BalanceCalculated);
|
||||||
AddAdjustment(AdjustableProperty.Frequency, component.FrequencyCalculated);
|
AddAdjustment(AdjustableProperty.Frequency, component.FrequencyCalculated);
|
||||||
AddAdjustment(AdjustableProperty.Volume, component.VolumeCalculated);
|
AddAdjustment(AdjustableProperty.Volume, component.VolumeCalculated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAdjustmentDependency(AdjustableAudioComponent component)
|
public void RemoveAdjustmentDependency(AdjustableAudioComponent component)
|
||||||
{
|
{
|
||||||
RemoveAdjustment(AdjustableProperty.Balance, component.BalanceCalculated);
|
RemoveAdjustment(AdjustableProperty.Balance, component.BalanceCalculated);
|
||||||
RemoveAdjustment(AdjustableProperty.Frequency, component.FrequencyCalculated);
|
RemoveAdjustment(AdjustableProperty.Frequency, component.FrequencyCalculated);
|
||||||
RemoveAdjustment(AdjustableProperty.Volume, component.VolumeCalculated);
|
RemoveAdjustment(AdjustableProperty.Volume, component.VolumeCalculated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
|
public void AddAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case AdjustableProperty.Balance:
|
case AdjustableProperty.Balance:
|
||||||
if (balanceAdjustments.Contains(adjustBindable))
|
if (balanceAdjustments.Contains(adjustBindable))
|
||||||
throw new ArgumentException("An adjustable binding may only be registered once.");
|
throw new ArgumentException("An adjustable binding may only be registered once.");
|
||||||
|
|
||||||
balanceAdjustments.Add(adjustBindable);
|
balanceAdjustments.Add(adjustBindable);
|
||||||
break;
|
break;
|
||||||
case AdjustableProperty.Frequency:
|
case AdjustableProperty.Frequency:
|
||||||
if (frequencyAdjustments.Contains(adjustBindable))
|
if (frequencyAdjustments.Contains(adjustBindable))
|
||||||
throw new ArgumentException("An adjustable binding may only be registered once.");
|
throw new ArgumentException("An adjustable binding may only be registered once.");
|
||||||
|
|
||||||
frequencyAdjustments.Add(adjustBindable);
|
frequencyAdjustments.Add(adjustBindable);
|
||||||
break;
|
break;
|
||||||
case AdjustableProperty.Volume:
|
case AdjustableProperty.Volume:
|
||||||
if (volumeAdjustments.Contains(adjustBindable))
|
if (volumeAdjustments.Contains(adjustBindable))
|
||||||
throw new ArgumentException("An adjustable binding may only be registered once.");
|
throw new ArgumentException("An adjustable binding may only be registered once.");
|
||||||
|
|
||||||
volumeAdjustments.Add(adjustBindable);
|
volumeAdjustments.Add(adjustBindable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidateState();
|
InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
|
public void RemoveAdjustment(AdjustableProperty type, BindableDouble adjustBindable)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case AdjustableProperty.Balance:
|
case AdjustableProperty.Balance:
|
||||||
balanceAdjustments.Remove(adjustBindable);
|
balanceAdjustments.Remove(adjustBindable);
|
||||||
break;
|
break;
|
||||||
case AdjustableProperty.Frequency:
|
case AdjustableProperty.Frequency:
|
||||||
frequencyAdjustments.Remove(adjustBindable);
|
frequencyAdjustments.Remove(adjustBindable);
|
||||||
break;
|
break;
|
||||||
case AdjustableProperty.Volume:
|
case AdjustableProperty.Volume:
|
||||||
volumeAdjustments.Remove(adjustBindable);
|
volumeAdjustments.Remove(adjustBindable);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidateState();
|
InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
volumeAdjustments.Clear();
|
volumeAdjustments.Clear();
|
||||||
balanceAdjustments.Clear();
|
balanceAdjustments.Clear();
|
||||||
frequencyAdjustments.Clear();
|
frequencyAdjustments.Clear();
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AdjustableProperty
|
public enum AdjustableProperty
|
||||||
{
|
{
|
||||||
Volume,
|
Volume,
|
||||||
Balance,
|
Balance,
|
||||||
Frequency
|
Frequency
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +1,82 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of audio components which need central property control.
|
/// A collection of audio components which need central property control.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioCollectionManager<T> : AdjustableAudioComponent
|
public class AudioCollectionManager<T> : AdjustableAudioComponent
|
||||||
where T : AdjustableAudioComponent
|
where T : AdjustableAudioComponent
|
||||||
{
|
{
|
||||||
protected List<T> Items = new List<T>();
|
protected List<T> Items = new List<T>();
|
||||||
|
|
||||||
public void AddItem(T item)
|
public void AddItem(T item)
|
||||||
{
|
{
|
||||||
RegisterItem(item);
|
RegisterItem(item);
|
||||||
AddItemToList(item);
|
AddItemToList(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddItemToList(T item)
|
public void AddItemToList(T item)
|
||||||
{
|
{
|
||||||
EnqueueAction(delegate
|
EnqueueAction(delegate
|
||||||
{
|
{
|
||||||
if (Items.Contains(item)) return;
|
if (Items.Contains(item)) return;
|
||||||
Items.Add(item);
|
Items.Add(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterItem(T item)
|
public void RegisterItem(T item)
|
||||||
{
|
{
|
||||||
EnqueueAction(() => item.AddAdjustmentDependency(this));
|
EnqueueAction(() => item.AddAdjustmentDependency(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnregisterItem(T item)
|
public void UnregisterItem(T item)
|
||||||
{
|
{
|
||||||
EnqueueAction(() => item.RemoveAdjustmentDependency(this));
|
EnqueueAction(() => item.RemoveAdjustmentDependency(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void OnStateChanged()
|
internal override void OnStateChanged()
|
||||||
{
|
{
|
||||||
base.OnStateChanged();
|
base.OnStateChanged();
|
||||||
foreach (var item in Items)
|
foreach (var item in Items)
|
||||||
item.OnStateChanged();
|
item.OnStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void UpdateDevice(int deviceIndex)
|
public virtual void UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
foreach (var item in Items.OfType<IBassAudio>())
|
foreach (var item in Items.OfType<IBassAudio>())
|
||||||
item.UpdateDevice(deviceIndex);
|
item.UpdateDevice(deviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateChildren()
|
protected override void UpdateChildren()
|
||||||
{
|
{
|
||||||
base.UpdateChildren();
|
base.UpdateChildren();
|
||||||
|
|
||||||
for (int i = 0; i < Items.Count; i++)
|
for (int i = 0; i < Items.Count; i++)
|
||||||
{
|
{
|
||||||
var item = Items[i];
|
var item = Items[i];
|
||||||
|
|
||||||
if (!item.IsAlive)
|
if (!item.IsAlive)
|
||||||
{
|
{
|
||||||
Items.RemoveAt(i--);
|
Items.RemoveAt(i--);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.Update();
|
item.Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
// we need to queue disposal of our Items before enqueueing the main dispose.
|
// we need to queue disposal of our Items before enqueueing the main dispose.
|
||||||
foreach (var i in Items)
|
foreach (var i in Items)
|
||||||
i.Dispose();
|
i.Dispose();
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,105 +1,105 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
public class AudioComponent : IDisposable, IUpdateable
|
public class AudioComponent : IDisposable, IUpdateable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Audio operations will be run on a separate dedicated thread, so we need to schedule any audio API calls using this queue.
|
/// Audio operations will be run on a separate dedicated thread, so we need to schedule any audio API calls using this queue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ConcurrentQueue<Task> PendingActions = new ConcurrentQueue<Task>();
|
protected ConcurrentQueue<Task> PendingActions = new ConcurrentQueue<Task>();
|
||||||
|
|
||||||
protected Task EnqueueAction(Action action)
|
protected Task EnqueueAction(Action action)
|
||||||
{
|
{
|
||||||
var task = new Task(action);
|
var task = new Task(action);
|
||||||
|
|
||||||
if (ThreadSafety.IsAudioThread)
|
if (ThreadSafety.IsAudioThread)
|
||||||
{
|
{
|
||||||
task.RunSynchronously();
|
task.RunSynchronously();
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!acceptingActions)
|
if (!acceptingActions)
|
||||||
// we don't want consumers to block on operations after we are disposed.
|
// we don't want consumers to block on operations after we are disposed.
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
PendingActions.Enqueue(task);
|
PendingActions.Enqueue(task);
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool acceptingActions = true;
|
private bool acceptingActions = true;
|
||||||
|
|
||||||
~AudioComponent()
|
~AudioComponent()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run each loop of the audio thread after queued actions to allow components to update anything they need to.
|
/// Run each loop of the audio thread after queued actions to allow components to update anything they need to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void UpdateState()
|
protected virtual void UpdateState()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateChildren()
|
protected virtual void UpdateChildren()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates this audio component. Always runs on the audio thread.
|
/// Updates this audio component. Always runs on the audio thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
ThreadSafety.EnsureNotUpdateThread();
|
ThreadSafety.EnsureNotUpdateThread();
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
throw new ObjectDisposedException(ToString(), "Can not update disposed audio components.");
|
throw new ObjectDisposedException(ToString(), "Can not update disposed audio components.");
|
||||||
|
|
||||||
FrameStatistics.Add(StatisticsCounterType.TasksRun, PendingActions.Count);
|
FrameStatistics.Add(StatisticsCounterType.TasksRun, PendingActions.Count);
|
||||||
FrameStatistics.Increment(StatisticsCounterType.Components);
|
FrameStatistics.Increment(StatisticsCounterType.Components);
|
||||||
|
|
||||||
while (!IsDisposed && PendingActions.TryDequeue(out Task task))
|
while (!IsDisposed && PendingActions.TryDequeue(out Task task))
|
||||||
task.RunSynchronously();
|
task.RunSynchronously();
|
||||||
|
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
UpdateState();
|
UpdateState();
|
||||||
|
|
||||||
UpdateChildren();
|
UpdateChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This component has completed playback and is now in a stopped state.
|
/// This component has completed playback and is now in a stopped state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool HasCompleted => !IsAlive;
|
public virtual bool HasCompleted => !IsAlive;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This component has completed all processing and is ready to be removed from its parent.
|
/// This component has completed all processing and is ready to be removed from its parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool IsAlive => !IsDisposed;
|
public virtual bool IsAlive => !IsDisposed;
|
||||||
|
|
||||||
public virtual bool IsLoaded => true;
|
public virtual bool IsLoaded => true;
|
||||||
|
|
||||||
#region IDisposable Support
|
#region IDisposable Support
|
||||||
|
|
||||||
protected volatile bool IsDisposed; // To detect redundant calls
|
protected volatile bool IsDisposed; // To detect redundant calls
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
acceptingActions = false;
|
acceptingActions = false;
|
||||||
PendingActions.Enqueue(new Task(() => Dispose(true)));
|
PendingActions.Enqueue(new Task(() => Dispose(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,378 +1,378 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using ManagedBass;
|
using ManagedBass;
|
||||||
using osu.Framework.Audio.Sample;
|
using osu.Framework.Audio.Sample;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using osu.Framework.Extensions.TypeExtensions;
|
using osu.Framework.Extensions.TypeExtensions;
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
public class AudioManager : AudioCollectionManager<AdjustableAudioComponent>
|
public class AudioManager : AudioCollectionManager<AdjustableAudioComponent>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The manager component responsible for audio tracks (e.g. songs).
|
/// The manager component responsible for audio tracks (e.g. songs).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TrackManager Track => GetTrackManager();
|
public TrackManager Track => GetTrackManager();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The manager component responsible for audio samples (e.g. sound effects).
|
/// The manager component responsible for audio samples (e.g. sound effects).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SampleManager Sample => GetSampleManager();
|
public SampleManager Sample => GetSampleManager();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The thread audio operations (mainly Bass calls) are ran on.
|
/// The thread audio operations (mainly Bass calls) are ran on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly AudioThread Thread;
|
internal readonly AudioThread Thread;
|
||||||
|
|
||||||
private List<DeviceInfo> audioDevices = new List<DeviceInfo>();
|
private List<DeviceInfo> audioDevices = new List<DeviceInfo>();
|
||||||
private List<string> audioDeviceNames = new List<string>();
|
private List<string> audioDeviceNames = new List<string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The names of all available audio devices.
|
/// The names of all available audio devices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<string> AudioDeviceNames => audioDeviceNames;
|
public IEnumerable<string> AudioDeviceNames => audioDeviceNames;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is fired whenever a new audio device is discovered and provides its name.
|
/// Is fired whenever a new audio device is discovered and provides its name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<string> OnNewDevice;
|
public event Action<string> OnNewDevice;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is fired whenever an audio device is lost and provides its name.
|
/// Is fired whenever an audio device is lost and provides its name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<string> OnLostDevice;
|
public event Action<string> OnLostDevice;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The preferred audio device we should use. A value of
|
/// The preferred audio device we should use. A value of
|
||||||
/// <see cref="string.Empty"/> denotes the OS default.
|
/// <see cref="string.Empty"/> denotes the OS default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Bindable<string> AudioDevice = new Bindable<string>();
|
public readonly Bindable<string> AudioDevice = new Bindable<string>();
|
||||||
|
|
||||||
private string currentAudioDevice;
|
private string currentAudioDevice;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Volume of all samples played game-wide.
|
/// Volume of all samples played game-wide.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble VolumeSample = new BindableDouble(1)
|
public readonly BindableDouble VolumeSample = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Volume of all tracks played game-wide.
|
/// Volume of all tracks played game-wide.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble VolumeTrack = new BindableDouble(1)
|
public readonly BindableDouble VolumeTrack = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 0,
|
MinValue = 0,
|
||||||
MaxValue = 1
|
MaxValue = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
private Scheduler scheduler => Thread.Scheduler;
|
private Scheduler scheduler => Thread.Scheduler;
|
||||||
|
|
||||||
private Scheduler eventScheduler => EventScheduler ?? scheduler;
|
private Scheduler eventScheduler => EventScheduler ?? scheduler;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The scheduler used for invoking publicly exposed delegate events.
|
/// The scheduler used for invoking publicly exposed delegate events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Scheduler EventScheduler;
|
public Scheduler EventScheduler;
|
||||||
|
|
||||||
private readonly Lazy<TrackManager> globalTrackManager;
|
private readonly Lazy<TrackManager> globalTrackManager;
|
||||||
private readonly Lazy<SampleManager> globalSampleManager;
|
private readonly Lazy<SampleManager> globalSampleManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an AudioManager given a track resource store, and a sample resource store.
|
/// Constructs an AudioManager given a track resource store, and a sample resource store.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="trackStore">The resource store containing all audio tracks to be used in the future.</param>
|
/// <param name="trackStore">The resource store containing all audio tracks to be used in the future.</param>
|
||||||
/// <param name="sampleStore">The sample store containing all audio samples to be used in the future.</param>
|
/// <param name="sampleStore">The sample store containing all audio samples to be used in the future.</param>
|
||||||
public AudioManager(ResourceStore<byte[]> trackStore, ResourceStore<byte[]> sampleStore)
|
public AudioManager(ResourceStore<byte[]> trackStore, ResourceStore<byte[]> sampleStore)
|
||||||
{
|
{
|
||||||
AudioDevice.ValueChanged += onDeviceChanged;
|
AudioDevice.ValueChanged += onDeviceChanged;
|
||||||
|
|
||||||
trackStore.AddExtension(@"mp3");
|
trackStore.AddExtension(@"mp3");
|
||||||
|
|
||||||
sampleStore.AddExtension(@"wav");
|
sampleStore.AddExtension(@"wav");
|
||||||
sampleStore.AddExtension(@"mp3");
|
sampleStore.AddExtension(@"mp3");
|
||||||
|
|
||||||
Thread = new AudioThread(Update);
|
Thread = new AudioThread(Update);
|
||||||
Thread.Start();
|
Thread.Start();
|
||||||
|
|
||||||
globalTrackManager = new Lazy<TrackManager>(() => GetTrackManager(trackStore));
|
globalTrackManager = new Lazy<TrackManager>(() => GetTrackManager(trackStore));
|
||||||
globalSampleManager = new Lazy<SampleManager>(() => GetSampleManager(sampleStore));
|
globalSampleManager = new Lazy<SampleManager>(() => GetSampleManager(sampleStore));
|
||||||
|
|
||||||
scheduler.Add(() =>
|
scheduler.Add(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
setAudioDevice();
|
setAudioDevice();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
scheduler.AddDelayed(delegate
|
scheduler.AddDelayed(delegate
|
||||||
{
|
{
|
||||||
updateAvailableAudioDevices();
|
updateAvailableAudioDevices();
|
||||||
checkAudioDeviceChanged();
|
checkAudioDeviceChanged();
|
||||||
}, 1000, true);
|
}, 1000, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
OnNewDevice = null;
|
OnNewDevice = null;
|
||||||
OnLostDevice = null;
|
OnLostDevice = null;
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDeviceChanged(string newDevice)
|
private void onDeviceChanged(string newDevice)
|
||||||
{
|
{
|
||||||
scheduler.Add(() => setAudioDevice(string.IsNullOrEmpty(newDevice) ? null : newDevice));
|
scheduler.Add(() => setAudioDevice(string.IsNullOrEmpty(newDevice) ? null : newDevice));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of the names of recognized audio devices.
|
/// Returns a list of the names of recognized audio devices.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The No Sound device that is in the list of Audio Devices that are stored internally is not returned.
|
/// The No Sound device that is in the list of Audio Devices that are stored internally is not returned.
|
||||||
/// Regarding the .Skip(1) as implementation for removing "No Sound", see http://bass.radio42.com/help/html/e5a666b4-1bdd-d1cb-555e-ce041997d52f.htm.
|
/// Regarding the .Skip(1) as implementation for removing "No Sound", see http://bass.radio42.com/help/html/e5a666b4-1bdd-d1cb-555e-ce041997d52f.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>A list of the names of recognized audio devices.</returns>
|
/// <returns>A list of the names of recognized audio devices.</returns>
|
||||||
private IEnumerable<string> getDeviceNames(List<DeviceInfo> devices) => devices.Skip(1).Select(d => d.Name);
|
private IEnumerable<string> getDeviceNames(List<DeviceInfo> devices) => devices.Skip(1).Select(d => d.Name);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Obtains the <see cref="TrackManager"/> corresponding to a given resource store.
|
/// Obtains the <see cref="TrackManager"/> corresponding to a given resource store.
|
||||||
/// Returns the global <see cref="TrackManager"/> if no resource store is passed.
|
/// Returns the global <see cref="TrackManager"/> if no resource store is passed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="store">The <see cref="T:ResourceStore"/> of which to retrieve the <see cref="TrackManager"/>.</param>
|
/// <param name="store">The <see cref="T:ResourceStore"/> of which to retrieve the <see cref="TrackManager"/>.</param>
|
||||||
public TrackManager GetTrackManager(ResourceStore<byte[]> store = null)
|
public TrackManager GetTrackManager(ResourceStore<byte[]> store = null)
|
||||||
{
|
{
|
||||||
if (store == null) return globalTrackManager.Value;
|
if (store == null) return globalTrackManager.Value;
|
||||||
|
|
||||||
TrackManager tm = new TrackManager(store);
|
TrackManager tm = new TrackManager(store);
|
||||||
AddItem(tm);
|
AddItem(tm);
|
||||||
tm.AddAdjustment(AdjustableProperty.Volume, VolumeTrack);
|
tm.AddAdjustment(AdjustableProperty.Volume, VolumeTrack);
|
||||||
VolumeTrack.ValueChanged += tm.InvalidateState;
|
VolumeTrack.ValueChanged += tm.InvalidateState;
|
||||||
|
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Obtains the <see cref="SampleManager"/> corresponding to a given resource store.
|
/// Obtains the <see cref="SampleManager"/> corresponding to a given resource store.
|
||||||
/// Returns the global <see cref="SampleManager"/> if no resource store is passed.
|
/// Returns the global <see cref="SampleManager"/> if no resource store is passed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="store">The <see cref="T:ResourceStore"/> of which to retrieve the <see cref="SampleManager"/>.</param>
|
/// <param name="store">The <see cref="T:ResourceStore"/> of which to retrieve the <see cref="SampleManager"/>.</param>
|
||||||
public SampleManager GetSampleManager(IResourceStore<byte[]> store = null)
|
public SampleManager GetSampleManager(IResourceStore<byte[]> store = null)
|
||||||
{
|
{
|
||||||
if (store == null) return globalSampleManager.Value;
|
if (store == null) return globalSampleManager.Value;
|
||||||
|
|
||||||
SampleManager sm = new SampleManager(store);
|
SampleManager sm = new SampleManager(store);
|
||||||
AddItem(sm);
|
AddItem(sm);
|
||||||
sm.AddAdjustment(AdjustableProperty.Volume, VolumeSample);
|
sm.AddAdjustment(AdjustableProperty.Volume, VolumeSample);
|
||||||
VolumeSample.ValueChanged += sm.InvalidateState;
|
VolumeSample.ValueChanged += sm.InvalidateState;
|
||||||
|
|
||||||
return sm;
|
return sm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<DeviceInfo> getAllDevices()
|
private List<DeviceInfo> getAllDevices()
|
||||||
{
|
{
|
||||||
int deviceCount = Bass.DeviceCount;
|
int deviceCount = Bass.DeviceCount;
|
||||||
List<DeviceInfo> info = new List<DeviceInfo>();
|
List<DeviceInfo> info = new List<DeviceInfo>();
|
||||||
for (int i = 0; i < deviceCount; i++)
|
for (int i = 0; i < deviceCount; i++)
|
||||||
info.Add(Bass.GetDeviceInfo(i));
|
info.Add(Bass.GetDeviceInfo(i));
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool setAudioDevice(string preferredDevice = null)
|
private bool setAudioDevice(string preferredDevice = null)
|
||||||
{
|
{
|
||||||
updateAvailableAudioDevices();
|
updateAvailableAudioDevices();
|
||||||
|
|
||||||
string oldDevice = currentAudioDevice;
|
string oldDevice = currentAudioDevice;
|
||||||
string newDevice = preferredDevice;
|
string newDevice = preferredDevice;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(newDevice))
|
if (string.IsNullOrEmpty(newDevice))
|
||||||
newDevice = audioDevices.Find(df => df.IsDefault).Name;
|
newDevice = audioDevices.Find(df => df.IsDefault).Name;
|
||||||
|
|
||||||
bool oldDeviceValid = Bass.CurrentDevice >= 0;
|
bool oldDeviceValid = Bass.CurrentDevice >= 0;
|
||||||
if (oldDeviceValid)
|
if (oldDeviceValid)
|
||||||
{
|
{
|
||||||
DeviceInfo oldDeviceInfo = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
DeviceInfo oldDeviceInfo = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
||||||
oldDeviceValid &= oldDeviceInfo.IsEnabled && oldDeviceInfo.IsInitialized;
|
oldDeviceValid &= oldDeviceInfo.IsEnabled && oldDeviceInfo.IsInitialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newDevice == oldDevice)
|
if (newDevice == oldDevice)
|
||||||
{
|
{
|
||||||
//check the old device is still valid
|
//check the old device is still valid
|
||||||
if (oldDeviceValid)
|
if (oldDeviceValid)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(newDevice))
|
if (string.IsNullOrEmpty(newDevice))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int newDeviceIndex = audioDevices.FindIndex(df => df.Name == newDevice);
|
int newDeviceIndex = audioDevices.FindIndex(df => df.Name == newDevice);
|
||||||
|
|
||||||
DeviceInfo newDeviceInfo = new DeviceInfo();
|
DeviceInfo newDeviceInfo = new DeviceInfo();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (newDeviceIndex >= 0)
|
if (newDeviceIndex >= 0)
|
||||||
newDeviceInfo = Bass.GetDeviceInfo(newDeviceIndex);
|
newDeviceInfo = Bass.GetDeviceInfo(newDeviceIndex);
|
||||||
//we may have previously initialised this device.
|
//we may have previously initialised this device.
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldDeviceValid && (newDeviceInfo.Driver == null || !newDeviceInfo.IsEnabled))
|
if (oldDeviceValid && (newDeviceInfo.Driver == null || !newDeviceInfo.IsEnabled))
|
||||||
{
|
{
|
||||||
//handles the case we are trying to load a user setting which is currently unavailable,
|
//handles the case we are trying to load a user setting which is currently unavailable,
|
||||||
//and we have already fallen back to a sane default.
|
//and we have already fallen back to a sane default.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Bass.Init(newDeviceIndex) && Bass.LastError != Errors.Already)
|
if (!Bass.Init(newDeviceIndex) && Bass.LastError != Errors.Already)
|
||||||
{
|
{
|
||||||
//the new device didn't go as planned. we need another option.
|
//the new device didn't go as planned. we need another option.
|
||||||
|
|
||||||
if (preferredDevice == null)
|
if (preferredDevice == null)
|
||||||
{
|
{
|
||||||
//we're fucked. the default device won't initialise.
|
//we're fucked. the default device won't initialise.
|
||||||
currentAudioDevice = null;
|
currentAudioDevice = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//let's try again using the default device.
|
//let's try again using the default device.
|
||||||
return setAudioDevice();
|
return setAudioDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Bass.LastError == Errors.Already)
|
if (Bass.LastError == Errors.Already)
|
||||||
{
|
{
|
||||||
// We check if the initialization error is that we already initialized the device
|
// We check if the initialization error is that we already initialized the device
|
||||||
// If it is, it means we can just tell Bass to use the already initialized device without much
|
// If it is, it means we can just tell Bass to use the already initialized device without much
|
||||||
// other fuzz.
|
// other fuzz.
|
||||||
Bass.CurrentDevice = newDeviceIndex;
|
Bass.CurrentDevice = newDeviceIndex;
|
||||||
Bass.Free();
|
Bass.Free();
|
||||||
Bass.Init(newDeviceIndex);
|
Bass.Init(newDeviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace.Assert(Bass.LastError == Errors.OK);
|
Trace.Assert(Bass.LastError == Errors.OK);
|
||||||
|
|
||||||
//we have successfully initialised a new device.
|
//we have successfully initialised a new device.
|
||||||
currentAudioDevice = newDevice;
|
currentAudioDevice = newDevice;
|
||||||
|
|
||||||
UpdateDevice(newDeviceIndex);
|
UpdateDevice(newDeviceIndex);
|
||||||
|
|
||||||
Bass.PlaybackBufferLength = 100;
|
Bass.PlaybackBufferLength = 100;
|
||||||
Bass.UpdatePeriod = 5;
|
Bass.UpdatePeriod = 5;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateDevice(int deviceIndex)
|
public override void UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
Sample.UpdateDevice(deviceIndex);
|
Sample.UpdateDevice(deviceIndex);
|
||||||
Track.UpdateDevice(deviceIndex);
|
Track.UpdateDevice(deviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAvailableAudioDevices()
|
private void updateAvailableAudioDevices()
|
||||||
{
|
{
|
||||||
var currentDeviceList = getAllDevices().Where(d => d.IsEnabled).ToList();
|
var currentDeviceList = getAllDevices().Where(d => d.IsEnabled).ToList();
|
||||||
var currentDeviceNames = getDeviceNames(currentDeviceList).ToList();
|
var currentDeviceNames = getDeviceNames(currentDeviceList).ToList();
|
||||||
|
|
||||||
var newDevices = currentDeviceNames.Except(audioDeviceNames).ToList();
|
var newDevices = currentDeviceNames.Except(audioDeviceNames).ToList();
|
||||||
var lostDevices = audioDeviceNames.Except(currentDeviceNames).ToList();
|
var lostDevices = audioDeviceNames.Except(currentDeviceNames).ToList();
|
||||||
|
|
||||||
if (newDevices.Count > 0 || lostDevices.Count > 0)
|
if (newDevices.Count > 0 || lostDevices.Count > 0)
|
||||||
{
|
{
|
||||||
eventScheduler.Add(delegate
|
eventScheduler.Add(delegate
|
||||||
{
|
{
|
||||||
foreach (var d in newDevices)
|
foreach (var d in newDevices)
|
||||||
OnNewDevice?.Invoke(d);
|
OnNewDevice?.Invoke(d);
|
||||||
foreach (var d in lostDevices)
|
foreach (var d in lostDevices)
|
||||||
OnLostDevice?.Invoke(d);
|
OnLostDevice?.Invoke(d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
audioDevices = currentDeviceList;
|
audioDevices = currentDeviceList;
|
||||||
audioDeviceNames = currentDeviceNames;
|
audioDeviceNames = currentDeviceNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAudioDeviceChanged()
|
private void checkAudioDeviceChanged()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (AudioDevice.Value == string.Empty)
|
if (AudioDevice.Value == string.Empty)
|
||||||
{
|
{
|
||||||
// use default device
|
// use default device
|
||||||
var device = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
var device = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
||||||
if (!device.IsDefault && !setAudioDevice())
|
if (!device.IsDefault && !setAudioDevice())
|
||||||
{
|
{
|
||||||
if (!device.IsEnabled || !setAudioDevice(device.Name))
|
if (!device.IsEnabled || !setAudioDevice(device.Name))
|
||||||
{
|
{
|
||||||
foreach (var d in getAllDevices())
|
foreach (var d in getAllDevices())
|
||||||
{
|
{
|
||||||
if (d.Name == device.Name || !d.IsEnabled)
|
if (d.Name == device.Name || !d.IsEnabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (setAudioDevice(d.Name))
|
if (setAudioDevice(d.Name))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// use whatever is the preferred device
|
// use whatever is the preferred device
|
||||||
var device = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
var device = Bass.GetDeviceInfo(Bass.CurrentDevice);
|
||||||
if (device.Name == AudioDevice.Value)
|
if (device.Name == AudioDevice.Value)
|
||||||
{
|
{
|
||||||
if (!device.IsEnabled && !setAudioDevice())
|
if (!device.IsEnabled && !setAudioDevice())
|
||||||
{
|
{
|
||||||
foreach (var d in getAllDevices())
|
foreach (var d in getAllDevices())
|
||||||
{
|
{
|
||||||
if (d.Name == device.Name || !d.IsEnabled)
|
if (d.Name == device.Name || !d.IsEnabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (setAudioDevice(d.Name))
|
if (setAudioDevice(d.Name))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var preferredDevice = getAllDevices().SingleOrDefault(d => d.Name == AudioDevice.Value);
|
var preferredDevice = getAllDevices().SingleOrDefault(d => d.Name == AudioDevice.Value);
|
||||||
if (preferredDevice.Name == AudioDevice.Value && preferredDevice.IsEnabled)
|
if (preferredDevice.Name == AudioDevice.Value && preferredDevice.IsEnabled)
|
||||||
setAudioDevice(preferredDevice.Name);
|
setAudioDevice(preferredDevice.Name);
|
||||||
else if (!device.IsEnabled && !setAudioDevice())
|
else if (!device.IsEnabled && !setAudioDevice())
|
||||||
{
|
{
|
||||||
foreach (var d in getAllDevices())
|
foreach (var d in getAllDevices())
|
||||||
{
|
{
|
||||||
if (d.Name == device.Name || !d.IsEnabled)
|
if (d.Name == device.Name || !d.IsEnabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (setAudioDevice(d.Name))
|
if (setAudioDevice(d.Name))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => $@"{GetType().ReadableName()} ({currentAudioDevice})";
|
public override string ToString() => $@"{GetType().ReadableName()} ({currentAudioDevice})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
internal interface IBassAudio
|
internal interface IBassAudio
|
||||||
{
|
{
|
||||||
void UpdateDevice(int deviceIndex);
|
void UpdateDevice(int deviceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
namespace osu.Framework.Audio
|
namespace osu.Framework.Audio
|
||||||
{
|
{
|
||||||
public interface IHasPitchAdjust
|
public interface IHasPitchAdjust
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pitch this track is playing at, relative to original.
|
/// The pitch this track is playing at, relative to original.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
double PitchAdjust { get; set; }
|
double PitchAdjust { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Sample
|
namespace osu.Framework.Audio.Sample
|
||||||
{
|
{
|
||||||
public abstract class Sample : AudioComponent
|
public abstract class Sample : AudioComponent
|
||||||
{
|
{
|
||||||
public const int DEFAULT_CONCURRENCY = 2;
|
public const int DEFAULT_CONCURRENCY = 2;
|
||||||
|
|
||||||
protected readonly int PlaybackConcurrency;
|
protected readonly int PlaybackConcurrency;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a new sample.
|
/// Construct a new sample.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="playbackConcurrency">How many instances of this sample should be allowed to playback concurrently before stopping the longest playing.</param>
|
/// <param name="playbackConcurrency">How many instances of this sample should be allowed to playback concurrently before stopping the longest playing.</param>
|
||||||
protected Sample(int playbackConcurrency = DEFAULT_CONCURRENCY)
|
protected Sample(int playbackConcurrency = DEFAULT_CONCURRENCY)
|
||||||
{
|
{
|
||||||
PlaybackConcurrency = playbackConcurrency;
|
PlaybackConcurrency = playbackConcurrency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using ManagedBass;
|
using ManagedBass;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Sample
|
namespace osu.Framework.Audio.Sample
|
||||||
{
|
{
|
||||||
internal class SampleBass : Sample, IBassAudio
|
internal class SampleBass : Sample, IBassAudio
|
||||||
{
|
{
|
||||||
private volatile int sampleId;
|
private volatile int sampleId;
|
||||||
|
|
||||||
public override bool IsLoaded => sampleId != 0;
|
public override bool IsLoaded => sampleId != 0;
|
||||||
|
|
||||||
public SampleBass(byte[] data, ConcurrentQueue<Task> customPendingActions = null, int concurrency = DEFAULT_CONCURRENCY)
|
public SampleBass(byte[] data, ConcurrentQueue<Task> customPendingActions = null, int concurrency = DEFAULT_CONCURRENCY)
|
||||||
: base(concurrency)
|
: base(concurrency)
|
||||||
{
|
{
|
||||||
if (customPendingActions != null)
|
if (customPendingActions != null)
|
||||||
PendingActions = customPendingActions;
|
PendingActions = customPendingActions;
|
||||||
|
|
||||||
EnqueueAction(() => { sampleId = Bass.SampleLoad(data, 0, data.Length, PlaybackConcurrency, BassFlags.Default | BassFlags.SampleOverrideLongestPlaying); });
|
EnqueueAction(() => { sampleId = Bass.SampleLoad(data, 0, data.Length, PlaybackConcurrency, BassFlags.Default | BassFlags.SampleOverrideLongestPlaying); });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Bass.SampleFree(sampleId);
|
Bass.SampleFree(sampleId);
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBassAudio.UpdateDevice(int deviceIndex)
|
void IBassAudio.UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
if (IsLoaded)
|
if (IsLoaded)
|
||||||
// counter-intuitively, this is the correct API to use to migrate a sample to a new device.
|
// counter-intuitively, this is the correct API to use to migrate a sample to a new device.
|
||||||
Bass.ChannelSetDevice(sampleId, deviceIndex);
|
Bass.ChannelSetDevice(sampleId, deviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CreateChannel() => Bass.SampleGetChannel(sampleId);
|
public int CreateChannel() => Bass.SampleGetChannel(sampleId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,56 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Sample
|
namespace osu.Framework.Audio.Sample
|
||||||
{
|
{
|
||||||
public abstract class SampleChannel : AdjustableAudioComponent
|
public abstract class SampleChannel : AdjustableAudioComponent
|
||||||
{
|
{
|
||||||
protected bool WasStarted;
|
protected bool WasStarted;
|
||||||
|
|
||||||
protected Sample Sample { get; set; }
|
protected Sample Sample { get; set; }
|
||||||
|
|
||||||
private readonly Action<SampleChannel> onPlay;
|
private readonly Action<SampleChannel> onPlay;
|
||||||
|
|
||||||
protected SampleChannel(Sample sample, Action<SampleChannel> onPlay)
|
protected SampleChannel(Sample sample, Action<SampleChannel> onPlay)
|
||||||
{
|
{
|
||||||
Sample = sample ?? throw new ArgumentNullException(nameof(sample));
|
Sample = sample ?? throw new ArgumentNullException(nameof(sample));
|
||||||
this.onPlay = onPlay;
|
this.onPlay = onPlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Play(bool restart = true)
|
public virtual void Play(bool restart = true)
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
throw new ObjectDisposedException(ToString(), "Can not play disposed samples.");
|
throw new ObjectDisposedException(ToString(), "Can not play disposed samples.");
|
||||||
|
|
||||||
onPlay(this);
|
onPlay(this);
|
||||||
WasStarted = true;
|
WasStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Stop()
|
public virtual void Stop()
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
throw new ObjectDisposedException(ToString(), "Can not stop disposed samples.");
|
throw new ObjectDisposedException(ToString(), "Can not stop disposed samples.");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
FrameStatistics.Increment(StatisticsCounterType.SChannels);
|
FrameStatistics.Increment(StatisticsCounterType.SChannels);
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract bool Playing { get; }
|
public abstract bool Playing { get; }
|
||||||
|
|
||||||
public virtual bool Played => WasStarted && !Playing;
|
public virtual bool Played => WasStarted && !Playing;
|
||||||
|
|
||||||
public override bool IsAlive => base.IsAlive && !Played;
|
public override bool IsAlive => base.IsAlive && !Played;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +1,97 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using ManagedBass;
|
using ManagedBass;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Sample
|
namespace osu.Framework.Audio.Sample
|
||||||
{
|
{
|
||||||
internal class SampleChannelBass : SampleChannel, IBassAudio
|
internal class SampleChannelBass : SampleChannel, IBassAudio
|
||||||
{
|
{
|
||||||
private volatile int channel;
|
private volatile int channel;
|
||||||
private volatile bool playing;
|
private volatile bool playing;
|
||||||
|
|
||||||
public override bool IsLoaded => Sample.IsLoaded;
|
public override bool IsLoaded => Sample.IsLoaded;
|
||||||
|
|
||||||
private float initialFrequency;
|
private float initialFrequency;
|
||||||
|
|
||||||
public SampleChannelBass(Sample sample, Action<SampleChannel> onPlay)
|
public SampleChannelBass(Sample sample, Action<SampleChannel> onPlay)
|
||||||
: base(sample, onPlay)
|
: base(sample, onPlay)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBassAudio.UpdateDevice(int deviceIndex)
|
void IBassAudio.UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
// Channels created from samples can not be migrated, so we need to ensure
|
// Channels created from samples can not be migrated, so we need to ensure
|
||||||
// a new channel is created after switching the device. We do not need to
|
// a new channel is created after switching the device. We do not need to
|
||||||
// manually free the channel, because our Bass.Free call upon switching devices
|
// manually free the channel, because our Bass.Free call upon switching devices
|
||||||
// takes care of that.
|
// takes care of that.
|
||||||
channel = 0;
|
channel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void OnStateChanged()
|
internal override void OnStateChanged()
|
||||||
{
|
{
|
||||||
base.OnStateChanged();
|
base.OnStateChanged();
|
||||||
|
|
||||||
if (channel != 0)
|
if (channel != 0)
|
||||||
{
|
{
|
||||||
Bass.ChannelSetAttribute(channel, ChannelAttribute.Volume, VolumeCalculated);
|
Bass.ChannelSetAttribute(channel, ChannelAttribute.Volume, VolumeCalculated);
|
||||||
Bass.ChannelSetAttribute(channel, ChannelAttribute.Pan, BalanceCalculated);
|
Bass.ChannelSetAttribute(channel, ChannelAttribute.Pan, BalanceCalculated);
|
||||||
Bass.ChannelSetAttribute(channel, ChannelAttribute.Frequency, initialFrequency * FrequencyCalculated);
|
Bass.ChannelSetAttribute(channel, ChannelAttribute.Frequency, initialFrequency * FrequencyCalculated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Play(bool restart = true)
|
public override void Play(bool restart = true)
|
||||||
{
|
{
|
||||||
EnqueueAction(() =>
|
EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
if (!IsLoaded)
|
if (!IsLoaded)
|
||||||
{
|
{
|
||||||
channel = 0;
|
channel = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are creating a new channel for every playback, since old channels may
|
// We are creating a new channel for every playback, since old channels may
|
||||||
// be overridden when too many other channels are created from the same sample.
|
// be overridden when too many other channels are created from the same sample.
|
||||||
channel = ((SampleBass)Sample).CreateChannel();
|
channel = ((SampleBass)Sample).CreateChannel();
|
||||||
Bass.ChannelGetAttribute(channel, ChannelAttribute.Frequency, out initialFrequency);
|
Bass.ChannelGetAttribute(channel, ChannelAttribute.Frequency, out initialFrequency);
|
||||||
});
|
});
|
||||||
|
|
||||||
InvalidateState();
|
InvalidateState();
|
||||||
|
|
||||||
EnqueueAction(() =>
|
EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
if (channel != 0)
|
if (channel != 0)
|
||||||
Bass.ChannelPlay(channel, restart);
|
Bass.ChannelPlay(channel, restart);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Needs to happen on the main thread such that
|
// Needs to happen on the main thread such that
|
||||||
// Played does not become true for a short moment.
|
// Played does not become true for a short moment.
|
||||||
playing = true;
|
playing = true;
|
||||||
|
|
||||||
base.Play(restart);
|
base.Play(restart);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
playing = channel != 0 && Bass.ChannelIsActive(channel) != 0;
|
playing = channel != 0 && Bass.ChannelIsActive(channel) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
if (channel == 0) return;
|
if (channel == 0) return;
|
||||||
|
|
||||||
base.Stop();
|
base.Stop();
|
||||||
|
|
||||||
EnqueueAction(() =>
|
EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
Bass.ChannelStop(channel);
|
Bass.ChannelStop(channel);
|
||||||
// ChannelStop frees the channel.
|
// ChannelStop frees the channel.
|
||||||
channel = 0;
|
channel = 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Playing => playing;
|
public override bool Playing => playing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,70 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Sample
|
namespace osu.Framework.Audio.Sample
|
||||||
{
|
{
|
||||||
public class SampleManager : AudioCollectionManager<SampleChannel>, IResourceStore<SampleChannel>
|
public class SampleManager : AudioCollectionManager<SampleChannel>, IResourceStore<SampleChannel>
|
||||||
{
|
{
|
||||||
private readonly IResourceStore<byte[]> store;
|
private readonly IResourceStore<byte[]> store;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, Sample> sampleCache = new ConcurrentDictionary<string, Sample>();
|
private readonly ConcurrentDictionary<string, Sample> sampleCache = new ConcurrentDictionary<string, Sample>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How many instances of a single sample should be allowed to playback concurrently before stopping the longest playing.
|
/// How many instances of a single sample should be allowed to playback concurrently before stopping the longest playing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int PlaybackConcurrency { get; set; } = Sample.DEFAULT_CONCURRENCY;
|
public int PlaybackConcurrency { get; set; } = Sample.DEFAULT_CONCURRENCY;
|
||||||
|
|
||||||
public SampleManager(IResourceStore<byte[]> store)
|
public SampleManager(IResourceStore<byte[]> store)
|
||||||
{
|
{
|
||||||
this.store = store;
|
this.store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SampleChannel Get(string name)
|
public SampleChannel Get(string name)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name)) return null;
|
if (string.IsNullOrEmpty(name)) return null;
|
||||||
|
|
||||||
lock (sampleCache)
|
lock (sampleCache)
|
||||||
{
|
{
|
||||||
SampleChannel channel = null;
|
SampleChannel channel = null;
|
||||||
if (!sampleCache.TryGetValue(name, out Sample sample))
|
if (!sampleCache.TryGetValue(name, out Sample sample))
|
||||||
{
|
{
|
||||||
byte[] data = store.Get(name);
|
byte[] data = store.Get(name);
|
||||||
sample = sampleCache[name] = data == null ? null : new SampleBass(data, PendingActions, PlaybackConcurrency);
|
sample = sampleCache[name] = data == null ? null : new SampleBass(data, PendingActions, PlaybackConcurrency);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sample != null)
|
if (sample != null)
|
||||||
{
|
{
|
||||||
channel = new SampleChannelBass(sample, AddItemToList);
|
channel = new SampleChannelBass(sample, AddItemToList);
|
||||||
RegisterItem(channel);
|
RegisterItem(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateDevice(int deviceIndex)
|
public override void UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
foreach (var sample in sampleCache.Values.OfType<IBassAudio>())
|
foreach (var sample in sampleCache.Values.OfType<IBassAudio>())
|
||||||
sample.UpdateDevice(deviceIndex);
|
sample.UpdateDevice(deviceIndex);
|
||||||
|
|
||||||
base.UpdateDevice(deviceIndex);
|
base.UpdateDevice(deviceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
FrameStatistics.Add(StatisticsCounterType.Samples, sampleCache.Count);
|
FrameStatistics.Add(StatisticsCounterType.Samples, sampleCache.Count);
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream GetStream(string name)
|
public Stream GetStream(string name)
|
||||||
{
|
{
|
||||||
return store.GetStream(name);
|
return store.GetStream(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +1,87 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ManagedBass;
|
using ManagedBass;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
internal class DataStreamFileProcedures
|
internal class DataStreamFileProcedures
|
||||||
{
|
{
|
||||||
private byte[] readBuffer = new byte[32768];
|
private byte[] readBuffer = new byte[32768];
|
||||||
|
|
||||||
private readonly Stream dataStream;
|
private readonly Stream dataStream;
|
||||||
|
|
||||||
public FileProcedures BassProcedures => new FileProcedures
|
public FileProcedures BassProcedures => new FileProcedures
|
||||||
{
|
{
|
||||||
Close = ac_Close,
|
Close = ac_Close,
|
||||||
Length = ac_Length,
|
Length = ac_Length,
|
||||||
Read = ac_Read,
|
Read = ac_Read,
|
||||||
Seek = ac_Seek
|
Seek = ac_Seek
|
||||||
};
|
};
|
||||||
|
|
||||||
public DataStreamFileProcedures(Stream data)
|
public DataStreamFileProcedures(Stream data)
|
||||||
{
|
{
|
||||||
dataStream = data;
|
dataStream = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ac_Close(IntPtr user)
|
private void ac_Close(IntPtr user)
|
||||||
{
|
{
|
||||||
//manually handle closing of stream
|
//manually handle closing of stream
|
||||||
}
|
}
|
||||||
|
|
||||||
private long ac_Length(IntPtr user)
|
private long ac_Length(IntPtr user)
|
||||||
{
|
{
|
||||||
if (dataStream == null) return 0;
|
if (dataStream == null) return 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return dataStream.Length;
|
return dataStream.Length;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ac_Read(IntPtr buffer, int length, IntPtr user)
|
private int ac_Read(IntPtr buffer, int length, IntPtr user)
|
||||||
{
|
{
|
||||||
if (dataStream == null) return 0;
|
if (dataStream == null) return 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (length > readBuffer.Length)
|
if (length > readBuffer.Length)
|
||||||
readBuffer = new byte[length];
|
readBuffer = new byte[length];
|
||||||
|
|
||||||
if (!dataStream.CanRead)
|
if (!dataStream.CanRead)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int readBytes = dataStream.Read(readBuffer, 0, length);
|
int readBytes = dataStream.Read(readBuffer, 0, length);
|
||||||
Marshal.Copy(readBuffer, 0, buffer, readBytes);
|
Marshal.Copy(readBuffer, 0, buffer, readBytes);
|
||||||
return readBytes;
|
return readBytes;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ac_Seek(long offset, IntPtr user)
|
private bool ac_Seek(long offset, IntPtr user)
|
||||||
{
|
{
|
||||||
if (dataStream == null) return false;
|
if (dataStream == null) return false;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return dataStream.Seek(offset, SeekOrigin.Begin) == offset;
|
return dataStream.Seek(offset, SeekOrigin.Begin) == offset;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,134 +1,134 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
public abstract class Track : AdjustableAudioComponent, IAdjustableClock
|
public abstract class Track : AdjustableAudioComponent, IAdjustableClock
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is this track capable of producing audio?
|
/// Is this track capable of producing audio?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool IsDummyDevice => true;
|
public virtual bool IsDummyDevice => true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// States if this track should repeat.
|
/// States if this track should repeat.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Looping { get; set; }
|
public bool Looping { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The speed of track playback. Does not affect pitch, but will reduce playback quality due to skipped frames.
|
/// The speed of track playback. Does not affect pitch, but will reduce playback quality due to skipped frames.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble Tempo = new BindableDouble(1);
|
public readonly BindableDouble Tempo = new BindableDouble(1);
|
||||||
|
|
||||||
protected Track()
|
protected Track()
|
||||||
{
|
{
|
||||||
Tempo.ValueChanged += InvalidateState;
|
Tempo.ValueChanged += InvalidateState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reset this track to a logical default state.
|
/// Reset this track to a logical default state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Reset()
|
public virtual void Reset()
|
||||||
{
|
{
|
||||||
Volume.Value = 1;
|
Volume.Value = 1;
|
||||||
|
|
||||||
ResetSpeedAdjustments();
|
ResetSpeedAdjustments();
|
||||||
|
|
||||||
Stop();
|
Stop();
|
||||||
Seek(0);
|
Seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restarts this track from the beginning while retaining adjustments.
|
/// Restarts this track from the beginning while retaining adjustments.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Restart()
|
public virtual void Restart()
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
Seek(0);
|
Seek(0);
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void ResetSpeedAdjustments()
|
public virtual void ResetSpeedAdjustments()
|
||||||
{
|
{
|
||||||
Frequency.Value = 1;
|
Frequency.Value = 1;
|
||||||
Tempo.Value = 1;
|
Tempo.Value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current position in milliseconds.
|
/// Current position in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract double CurrentTime { get; }
|
public abstract double CurrentTime { get; }
|
||||||
|
|
||||||
private double length;
|
private double length;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Length of the track in milliseconds.
|
/// Length of the track in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Length
|
public double Length
|
||||||
{
|
{
|
||||||
get => length;
|
get => length;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw new ArgumentException("Track length must be >= 0.", nameof(value));
|
throw new ArgumentException("Track length must be >= 0.", nameof(value));
|
||||||
length = value;
|
length = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual int? Bitrate => null;
|
public virtual int? Bitrate => null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Seek to a new position.
|
/// Seek to a new position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="seek">New position in milliseconds</param>
|
/// <param name="seek">New position in milliseconds</param>
|
||||||
/// <returns>Whether the seek was successful.</returns>
|
/// <returns>Whether the seek was successful.</returns>
|
||||||
public abstract bool Seek(double seek);
|
public abstract bool Seek(double seek);
|
||||||
|
|
||||||
public virtual void Start()
|
public virtual void Start()
|
||||||
{
|
{
|
||||||
if (IsDisposed)
|
if (IsDisposed)
|
||||||
throw new ObjectDisposedException(ToString(), "Can not start disposed tracks.");
|
throw new ObjectDisposedException(ToString(), "Can not start disposed tracks.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Stop()
|
public virtual void Stop()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract bool IsRunning { get; }
|
public abstract bool IsRunning { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Overall playback rate (1 is 100%, -1 is reversed at 100%).
|
/// Overall playback rate (1 is 100%, -1 is reversed at 100%).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual double Rate
|
public virtual double Rate
|
||||||
{
|
{
|
||||||
get { return Frequency * Tempo; }
|
get { return Frequency * Tempo; }
|
||||||
set { Tempo.Value = value; }
|
set { Tempo.Value = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsReversed => Rate < 0;
|
public bool IsReversed => Rate < 0;
|
||||||
|
|
||||||
public override bool HasCompleted => IsLoaded && !IsRunning && CurrentTime >= Length;
|
public override bool HasCompleted => IsLoaded && !IsRunning && CurrentTime >= Length;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current amplitude of stereo channels where 1 is full volume and 0 is silent.
|
/// Current amplitude of stereo channels where 1 is full volume and 0 is silent.
|
||||||
/// LeftChannel and RightChannel represent the maximum current amplitude of all of the left and right channels respectively.
|
/// LeftChannel and RightChannel represent the maximum current amplitude of all of the left and right channels respectively.
|
||||||
/// The most recent values are returned. Synchronisation between channels should not be expected.
|
/// The most recent values are returned. Synchronisation between channels should not be expected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual TrackAmplitudes CurrentAmplitudes => new TrackAmplitudes();
|
public virtual TrackAmplitudes CurrentAmplitudes => new TrackAmplitudes();
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
FrameStatistics.Increment(StatisticsCounterType.Tracks);
|
FrameStatistics.Increment(StatisticsCounterType.Tracks);
|
||||||
|
|
||||||
if (Looping && HasCompleted)
|
if (Looping && HasCompleted)
|
||||||
Restart();
|
Restart();
|
||||||
|
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
public struct TrackAmplitudes
|
public struct TrackAmplitudes
|
||||||
{
|
{
|
||||||
public float LeftChannel;
|
public float LeftChannel;
|
||||||
public float RightChannel;
|
public float RightChannel;
|
||||||
|
|
||||||
public float Maximum => Math.Max(LeftChannel, RightChannel);
|
public float Maximum => Math.Max(LeftChannel, RightChannel);
|
||||||
|
|
||||||
public float Average => (LeftChannel + RightChannel) / 2;
|
public float Average => (LeftChannel + RightChannel) / 2;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 256 length array of bins containing the average frequency of both channels at every ~78Hz step of the audible spectrum (0Hz - 20,000Hz).
|
/// 256 length array of bins containing the average frequency of both channels at every ~78Hz step of the audible spectrum (0Hz - 20,000Hz).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float[] FrequencyAmplitudes;
|
public float[] FrequencyAmplitudes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,248 +1,248 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ManagedBass;
|
using ManagedBass;
|
||||||
using ManagedBass.Fx;
|
using ManagedBass.Fx;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
using osu.Framework.IO;
|
using osu.Framework.IO;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
public class TrackBass : Track, IBassAudio, IHasPitchAdjust
|
public class TrackBass : Track, IBassAudio, IHasPitchAdjust
|
||||||
{
|
{
|
||||||
private AsyncBufferStream dataStream;
|
private AsyncBufferStream dataStream;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should this track only be used for preview purposes? This suggests it has not yet been fully loaded.
|
/// Should this track only be used for preview purposes? This suggests it has not yet been fully loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Preview { get; private set; }
|
public bool Preview { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The handle for this track, if there is one.
|
/// The handle for this track, if there is one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int activeStream;
|
private int activeStream;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The handle for adjusting tempo.
|
/// The handle for adjusting tempo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int tempoAdjustStream;
|
private int tempoAdjustStream;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This marks if the track is paused, or stopped to the end.
|
/// This marks if the track is paused, or stopped to the end.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool isPlayed;
|
private bool isPlayed;
|
||||||
|
|
||||||
private volatile bool isLoaded;
|
private volatile bool isLoaded;
|
||||||
|
|
||||||
public override bool IsLoaded => isLoaded;
|
public override bool IsLoaded => isLoaded;
|
||||||
|
|
||||||
public TrackBass(Stream data, bool quick = false)
|
public TrackBass(Stream data, bool quick = false)
|
||||||
{
|
{
|
||||||
EnqueueAction(() =>
|
EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
Preview = quick;
|
Preview = quick;
|
||||||
|
|
||||||
if (data == null)
|
if (data == null)
|
||||||
throw new ArgumentNullException(nameof(data));
|
throw new ArgumentNullException(nameof(data));
|
||||||
//encapsulate incoming stream with async buffer if it isn't already.
|
//encapsulate incoming stream with async buffer if it isn't already.
|
||||||
dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1);
|
dataStream = data as AsyncBufferStream ?? new AsyncBufferStream(data, quick ? 8 : -1);
|
||||||
|
|
||||||
var procs = new DataStreamFileProcedures(dataStream);
|
var procs = new DataStreamFileProcedures(dataStream);
|
||||||
|
|
||||||
BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan | BassFlags.Float;
|
BassFlags flags = Preview ? 0 : BassFlags.Decode | BassFlags.Prescan | BassFlags.Float;
|
||||||
activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, procs.BassProcedures, IntPtr.Zero);
|
activeStream = Bass.CreateStream(StreamSystem.NoBuffer, flags, procs.BassProcedures, IntPtr.Zero);
|
||||||
|
|
||||||
if (!Preview)
|
if (!Preview)
|
||||||
{
|
{
|
||||||
// We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting
|
// We assign the BassFlags.Decode streams to the device "bass_nodevice" to prevent them from getting
|
||||||
// cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices.
|
// cleaned up during a Bass.Free call. This is necessary for seamless switching between audio devices.
|
||||||
// Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees
|
// Further, we provide the flag BassFlags.FxFreeSource such that freeing the activeStream also frees
|
||||||
// all parent decoding streams.
|
// all parent decoding streams.
|
||||||
const int bass_nodevice = 0x20000;
|
const int bass_nodevice = 0x20000;
|
||||||
|
|
||||||
Bass.ChannelSetDevice(activeStream, bass_nodevice);
|
Bass.ChannelSetDevice(activeStream, bass_nodevice);
|
||||||
tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource);
|
tempoAdjustStream = BassFx.TempoCreate(activeStream, BassFlags.Decode | BassFlags.FxFreeSource);
|
||||||
Bass.ChannelSetDevice(activeStream, bass_nodevice);
|
Bass.ChannelSetDevice(activeStream, bass_nodevice);
|
||||||
activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource);
|
activeStream = BassFx.ReverseCreate(tempoAdjustStream, 5f, BassFlags.Default | BassFlags.FxFreeSource);
|
||||||
|
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoUseQuickAlgorithm, 1);
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoOverlapMilliseconds, 4);
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.TempoSequenceMilliseconds, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
Length = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)) * 1000;
|
Length = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetLength(activeStream)) * 1000;
|
||||||
|
|
||||||
Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency);
|
Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency);
|
||||||
initialFrequency = frequency;
|
initialFrequency = frequency;
|
||||||
bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate);
|
bitrate = (int)Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Bitrate);
|
||||||
|
|
||||||
isLoaded = true;
|
isLoaded = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
InvalidateState();
|
InvalidateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IBassAudio.UpdateDevice(int deviceIndex)
|
void IBassAudio.UpdateDevice(int deviceIndex)
|
||||||
{
|
{
|
||||||
Bass.ChannelSetDevice(activeStream, deviceIndex);
|
Bass.ChannelSetDevice(activeStream, deviceIndex);
|
||||||
Trace.Assert(Bass.LastError == Errors.OK);
|
Trace.Assert(Bass.LastError == Errors.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
isRunning = Bass.ChannelIsActive(activeStream) == PlaybackState.Playing;
|
isRunning = Bass.ChannelIsActive(activeStream) == PlaybackState.Playing;
|
||||||
|
|
||||||
double currentTimeLocal = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetPosition(activeStream)) * 1000;
|
double currentTimeLocal = Bass.ChannelBytes2Seconds(activeStream, Bass.ChannelGetPosition(activeStream)) * 1000;
|
||||||
Interlocked.Exchange(ref currentTime, currentTimeLocal == Length && !isPlayed ? 0 : currentTimeLocal);
|
Interlocked.Exchange(ref currentTime, currentTimeLocal == Length && !isPlayed ? 0 : currentTimeLocal);
|
||||||
|
|
||||||
var leftChannel = isPlayed ? Bass.ChannelGetLevelLeft(activeStream) / 32768f : -1;
|
var leftChannel = isPlayed ? Bass.ChannelGetLevelLeft(activeStream) / 32768f : -1;
|
||||||
var rightChannel = isPlayed ? Bass.ChannelGetLevelRight(activeStream) / 32768f : -1;
|
var rightChannel = isPlayed ? Bass.ChannelGetLevelRight(activeStream) / 32768f : -1;
|
||||||
|
|
||||||
if (leftChannel >= 0 && rightChannel >= 0)
|
if (leftChannel >= 0 && rightChannel >= 0)
|
||||||
{
|
{
|
||||||
currentAmplitudes.LeftChannel = leftChannel;
|
currentAmplitudes.LeftChannel = leftChannel;
|
||||||
currentAmplitudes.RightChannel = rightChannel;
|
currentAmplitudes.RightChannel = rightChannel;
|
||||||
|
|
||||||
float[] tempFrequencyData = new float[256];
|
float[] tempFrequencyData = new float[256];
|
||||||
Bass.ChannelGetData(activeStream, tempFrequencyData, (int)DataFlags.FFT512);
|
Bass.ChannelGetData(activeStream, tempFrequencyData, (int)DataFlags.FFT512);
|
||||||
currentAmplitudes.FrequencyAmplitudes = tempFrequencyData;
|
currentAmplitudes.FrequencyAmplitudes = tempFrequencyData;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentAmplitudes.LeftChannel = 0;
|
currentAmplitudes.LeftChannel = 0;
|
||||||
currentAmplitudes.RightChannel = 0;
|
currentAmplitudes.RightChannel = 0;
|
||||||
currentAmplitudes.FrequencyAmplitudes = new float[256];
|
currentAmplitudes.FrequencyAmplitudes = new float[256];
|
||||||
}
|
}
|
||||||
|
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (activeStream != 0)
|
if (activeStream != 0)
|
||||||
{
|
{
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
Bass.ChannelStop(activeStream);
|
Bass.ChannelStop(activeStream);
|
||||||
Bass.StreamFree(activeStream);
|
Bass.StreamFree(activeStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
activeStream = 0;
|
activeStream = 0;
|
||||||
|
|
||||||
dataStream?.Dispose();
|
dataStream?.Dispose();
|
||||||
dataStream = null;
|
dataStream = null;
|
||||||
|
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsDummyDevice => false;
|
public override bool IsDummyDevice => false;
|
||||||
|
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
base.Stop();
|
base.Stop();
|
||||||
StopAsync().Wait();
|
StopAsync().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopAsync()
|
public async Task StopAsync()
|
||||||
{
|
{
|
||||||
await EnqueueAction(() =>
|
await EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
if (Bass.ChannelIsActive(activeStream) == PlaybackState.Playing)
|
if (Bass.ChannelIsActive(activeStream) == PlaybackState.Playing)
|
||||||
Bass.ChannelPause(activeStream);
|
Bass.ChannelPause(activeStream);
|
||||||
|
|
||||||
isPlayed = false;
|
isPlayed = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private int direction;
|
private int direction;
|
||||||
|
|
||||||
private void setDirection(bool reverse)
|
private void setDirection(bool reverse)
|
||||||
{
|
{
|
||||||
direction = reverse ? -1 : 1;
|
direction = reverse ? -1 : 1;
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.ReverseDirection, direction);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.ReverseDirection, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
base.Start();
|
base.Start();
|
||||||
|
|
||||||
StartAsync().Wait();
|
StartAsync().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartAsync()
|
public async Task StartAsync()
|
||||||
{
|
{
|
||||||
await EnqueueAction(() =>
|
await EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
if (Bass.ChannelPlay(activeStream))
|
if (Bass.ChannelPlay(activeStream))
|
||||||
isPlayed = true;
|
isPlayed = true;
|
||||||
else
|
else
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Seek(double seek) => SeekAsync(seek).Result;
|
public override bool Seek(double seek) => SeekAsync(seek).Result;
|
||||||
|
|
||||||
public async Task<bool> SeekAsync(double seek)
|
public async Task<bool> SeekAsync(double seek)
|
||||||
{
|
{
|
||||||
// At this point the track may not yet be loaded which is indicated by a 0 length.
|
// At this point the track may not yet be loaded which is indicated by a 0 length.
|
||||||
// In that case we still want to return true, hence the conservative length.
|
// In that case we still want to return true, hence the conservative length.
|
||||||
double conservativeLength = Length == 0 ? double.MaxValue : Length;
|
double conservativeLength = Length == 0 ? double.MaxValue : Length;
|
||||||
double conservativeClamped = MathHelper.Clamp(seek, 0, conservativeLength);
|
double conservativeClamped = MathHelper.Clamp(seek, 0, conservativeLength);
|
||||||
|
|
||||||
await EnqueueAction(() =>
|
await EnqueueAction(() =>
|
||||||
{
|
{
|
||||||
double clamped = MathHelper.Clamp(seek, 0, Length);
|
double clamped = MathHelper.Clamp(seek, 0, Length);
|
||||||
|
|
||||||
if (clamped != CurrentTime)
|
if (clamped != CurrentTime)
|
||||||
{
|
{
|
||||||
long pos = Bass.ChannelSeconds2Bytes(activeStream, clamped / 1000d);
|
long pos = Bass.ChannelSeconds2Bytes(activeStream, clamped / 1000d);
|
||||||
Bass.ChannelSetPosition(activeStream, pos);
|
Bass.ChannelSetPosition(activeStream, pos);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return conservativeClamped == seek;
|
return conservativeClamped == seek;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double currentTime;
|
private double currentTime;
|
||||||
|
|
||||||
public override double CurrentTime => currentTime;
|
public override double CurrentTime => currentTime;
|
||||||
|
|
||||||
private volatile bool isRunning;
|
private volatile bool isRunning;
|
||||||
|
|
||||||
public override bool IsRunning => isRunning;
|
public override bool IsRunning => isRunning;
|
||||||
|
|
||||||
internal override void OnStateChanged()
|
internal override void OnStateChanged()
|
||||||
{
|
{
|
||||||
base.OnStateChanged();
|
base.OnStateChanged();
|
||||||
|
|
||||||
setDirection(FrequencyCalculated.Value < 0);
|
setDirection(FrequencyCalculated.Value < 0);
|
||||||
|
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Volume, VolumeCalculated);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Volume, VolumeCalculated);
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Pan, BalanceCalculated);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Pan, BalanceCalculated);
|
||||||
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Frequency, bassFreq);
|
Bass.ChannelSetAttribute(activeStream, ChannelAttribute.Frequency, bassFreq);
|
||||||
Bass.ChannelSetAttribute(tempoAdjustStream, ChannelAttribute.Tempo, (Math.Abs(Tempo) - 1) * 100);
|
Bass.ChannelSetAttribute(tempoAdjustStream, ChannelAttribute.Tempo, (Math.Abs(Tempo) - 1) * 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
private volatile float initialFrequency;
|
private volatile float initialFrequency;
|
||||||
|
|
||||||
private int bassFreq => (int)MathHelper.Clamp(Math.Abs(initialFrequency * FrequencyCalculated), 100, 100000);
|
private int bassFreq => (int)MathHelper.Clamp(Math.Abs(initialFrequency * FrequencyCalculated), 100, 100000);
|
||||||
|
|
||||||
private volatile int bitrate;
|
private volatile int bitrate;
|
||||||
|
|
||||||
public override int? Bitrate => bitrate;
|
public override int? Bitrate => bitrate;
|
||||||
|
|
||||||
public double PitchAdjust
|
public double PitchAdjust
|
||||||
{
|
{
|
||||||
get { return Frequency.Value; }
|
get { return Frequency.Value; }
|
||||||
set { Frequency.Value = value; }
|
set { Frequency.Value = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private TrackAmplitudes currentAmplitudes;
|
private TrackAmplitudes currentAmplitudes;
|
||||||
|
|
||||||
public override TrackAmplitudes CurrentAmplitudes => currentAmplitudes;
|
public override TrackAmplitudes CurrentAmplitudes => currentAmplitudes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
public class TrackManager : AudioCollectionManager<Track>
|
public class TrackManager : AudioCollectionManager<Track>
|
||||||
{
|
{
|
||||||
private readonly IResourceStore<byte[]> store;
|
private readonly IResourceStore<byte[]> store;
|
||||||
|
|
||||||
public TrackManager(IResourceStore<byte[]> store)
|
public TrackManager(IResourceStore<byte[]> store)
|
||||||
{
|
{
|
||||||
this.store = store;
|
this.store = store;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Track Get(string name)
|
public Track Get(string name)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name)) return null;
|
if (string.IsNullOrEmpty(name)) return null;
|
||||||
|
|
||||||
TrackBass track = new TrackBass(store.GetStream(name));
|
TrackBass track = new TrackBass(store.GetStream(name));
|
||||||
AddItem(track);
|
AddItem(track);
|
||||||
return track;
|
return track;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +1,92 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||||
|
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using OpenTK;
|
using OpenTK;
|
||||||
|
|
||||||
namespace osu.Framework.Audio.Track
|
namespace osu.Framework.Audio.Track
|
||||||
{
|
{
|
||||||
public class TrackVirtual : Track
|
public class TrackVirtual : Track
|
||||||
{
|
{
|
||||||
private readonly StopwatchClock clock = new StopwatchClock();
|
private readonly StopwatchClock clock = new StopwatchClock();
|
||||||
|
|
||||||
private double seekOffset;
|
private double seekOffset;
|
||||||
|
|
||||||
public TrackVirtual()
|
public TrackVirtual()
|
||||||
{
|
{
|
||||||
Length = double.PositiveInfinity;
|
Length = double.PositiveInfinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Seek(double seek)
|
public override bool Seek(double seek)
|
||||||
{
|
{
|
||||||
double current = CurrentTime;
|
double current = CurrentTime;
|
||||||
|
|
||||||
seekOffset = seek;
|
seekOffset = seek;
|
||||||
|
|
||||||
lock (clock)
|
lock (clock)
|
||||||
{
|
{
|
||||||
if (IsRunning)
|
if (IsRunning)
|
||||||
clock.Restart();
|
clock.Restart();
|
||||||
else
|
else
|
||||||
clock.Reset();
|
clock.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
seekOffset = MathHelper.Clamp(seekOffset, 0, Length);
|
seekOffset = MathHelper.Clamp(seekOffset, 0, Length);
|
||||||
|
|
||||||
return current != seekOffset;
|
return current != seekOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
lock (clock) clock.Start();
|
lock (clock) clock.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Reset()
|
public override void Reset()
|
||||||
{
|
{
|
||||||
lock (clock) clock.Reset();
|
lock (clock) clock.Reset();
|
||||||
seekOffset = 0;
|
seekOffset = 0;
|
||||||
|
|
||||||
base.Reset();
|
base.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
lock (clock) clock.Stop();
|
lock (clock) clock.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsRunning
|
public override bool IsRunning
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (clock) return clock.IsRunning;
|
lock (clock) return clock.IsRunning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double CurrentTime
|
public override double CurrentTime
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (clock) return seekOffset + clock.CurrentTime;
|
lock (clock) return seekOffset + clock.CurrentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
base.UpdateState();
|
base.UpdateState();
|
||||||
|
|
||||||
lock (clock)
|
lock (clock)
|
||||||
{
|
{
|
||||||
if (CurrentTime >= Length)
|
if (CurrentTime >= Length)
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void OnStateChanged()
|
internal override void OnStateChanged()
|
||||||
{
|
{
|
||||||
base.OnStateChanged();
|
base.OnStateChanged();
|
||||||
|
|
||||||
lock (clock)
|
lock (clock)
|
||||||
clock.Rate = Tempo;
|
clock.Rate = Tempo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user