2019-01-24 16:43:03 +08:00
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
using System ;
using System.Collections.Generic ;
using osu.Framework.Configuration ;
using osu.Framework.Configuration.Tracking ;
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
2018-07-09 16:53:39 +08:00
using osu.Framework.Graphics.Transforms ;
using osu.Framework.Threading ;
2019-07-05 22:03:22 +08:00
using osu.Game.Overlays.OSD ;
2020-11-11 12:51:20 +08:00
using osuTK ;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Overlays
{
2019-08-12 16:53:06 +08:00
/// <summary>
/// An on-screen display which automatically tracks and displays toast notifications for <seealso cref="TrackedSettings"/>.
/// Can also display custom content via <see cref="Display(Toast)"/>
/// </summary>
2018-04-13 17:19:50 +08:00
public class OnScreenDisplay : Container
{
private readonly Container box ;
private const float height = 110 ;
private const float height_contracted = height * 0.9f ;
public OnScreenDisplay ( )
{
RelativeSizeAxes = Axes . Both ;
Children = new Drawable [ ]
{
box = new Container
{
Origin = Anchor . Centre ,
RelativePositionAxes = Axes . Both ,
Position = new Vector2 ( 0.5f , 0.75f ) ,
Masking = true ,
AutoSizeAxes = Axes . X ,
Height = height_contracted ,
Alpha = 0 ,
CornerRadius = 20 ,
} ,
} ;
}
private readonly Dictionary < ( object , IConfigManager ) , TrackedSettings > trackedConfigManagers = new Dictionary < ( object , IConfigManager ) , TrackedSettings > ( ) ;
/// <summary>
/// Registers a <see cref="ConfigManager{T}"/> to have its settings tracked by this <see cref="OnScreenDisplay"/>.
/// </summary>
/// <param name="source">The object that is registering the <see cref="ConfigManager{T}"/> to be tracked.</param>
/// <param name="configManager">The <see cref="ConfigManager{T}"/> to be tracked.</param>
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
public void BeginTracking ( object source , ITrackableConfigManager configManager )
{
2018-07-09 16:53:39 +08:00
if ( configManager = = null ) throw new ArgumentNullException ( nameof ( configManager ) ) ;
2018-04-13 17:19:50 +08:00
if ( trackedConfigManagers . ContainsKey ( ( source , configManager ) ) )
throw new InvalidOperationException ( $"{nameof(configManager)} is already registered." ) ;
var trackedSettings = configManager . CreateTrackedSettings ( ) ;
if ( trackedSettings = = null )
return ;
configManager . LoadInto ( trackedSettings ) ;
2019-07-05 22:03:22 +08:00
trackedSettings . SettingChanged + = displayTrackedSettingChange ;
2018-04-13 17:19:50 +08:00
trackedConfigManagers . Add ( ( source , configManager ) , trackedSettings ) ;
}
/// <summary>
/// Unregisters a <see cref="ConfigManager{T}"/> from having its settings tracked by this <see cref="OnScreenDisplay"/>.
/// </summary>
/// <param name="source">The object that registered the <see cref="ConfigManager{T}"/> to be tracked.</param>
/// <param name="configManager">The <see cref="ConfigManager{T}"/> that is being tracked.</param>
/// <exception cref="ArgumentNullException">If <paramref name="configManager"/> is null.</exception>
2019-11-17 20:49:36 +08:00
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <paramref name="source"/>.</exception>
2018-04-13 17:19:50 +08:00
public void StopTracking ( object source , ITrackableConfigManager configManager )
{
2018-07-09 16:53:39 +08:00
if ( configManager = = null ) throw new ArgumentNullException ( nameof ( configManager ) ) ;
2018-04-13 17:19:50 +08:00
if ( ! trackedConfigManagers . TryGetValue ( ( source , configManager ) , out var existing ) )
2019-01-24 23:02:47 +08:00
return ;
2018-04-13 17:19:50 +08:00
existing . Unload ( ) ;
2019-07-05 22:03:22 +08:00
existing . SettingChanged - = displayTrackedSettingChange ;
2018-04-13 17:19:50 +08:00
trackedConfigManagers . Remove ( ( source , configManager ) ) ;
}
2019-07-05 22:03:22 +08:00
/// <summary>
2019-08-12 16:53:06 +08:00
/// Displays the provided <see cref="Toast"/> temporarily.
2019-07-05 22:03:22 +08:00
/// </summary>
/// <param name="toast"></param>
2021-12-01 00:55:14 +08:00
public void Display ( Toast toast ) = > Schedule ( ( ) = >
2018-04-13 17:19:50 +08:00
{
2019-07-05 22:03:22 +08:00
box . Child = toast ;
DisplayTemporarily ( box ) ;
2021-12-01 00:55:14 +08:00
} ) ;
2018-04-13 17:19:50 +08:00
2021-12-01 00:55:14 +08:00
private void displayTrackedSettingChange ( SettingDescription description ) = > Display ( new TrackedSettingToast ( description ) ) ;
2019-07-05 22:03:22 +08:00
2018-07-09 16:53:39 +08:00
private TransformSequence < Drawable > fadeIn ;
private ScheduledDelegate fadeOut ;
protected virtual void DisplayTemporarily ( Drawable toDisplay )
2018-05-10 14:49:37 +08:00
{
2018-07-09 16:53:39 +08:00
// avoid starting a new fade-in if one is already active.
if ( fadeIn = = null )
{
fadeIn = toDisplay . Animate (
b = > b . FadeIn ( 500 , Easing . OutQuint ) ,
b = > b . ResizeHeightTo ( height , 500 , Easing . OutQuint )
) ;
fadeIn . Finally ( _ = > fadeIn = null ) ;
}
fadeOut ? . Cancel ( ) ;
fadeOut = Scheduler . AddDelayed ( ( ) = >
{
toDisplay . Animate (
b = > b . FadeOutFromOne ( 1500 , Easing . InQuint ) ,
b = > b . ResizeHeightTo ( height_contracted , 1500 , Easing . InQuint ) ) ;
} , 500 ) ;
2018-05-10 14:49:37 +08:00
}
2018-04-13 17:19:50 +08:00
}
}