2019-09-21 17:10:04 +00: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.
2019-09-22 19:22:50 +00:00
using System ;
2019-11-12 02:04:49 +00:00
using System.Collections.Generic ;
2020-03-13 06:44:13 +00:00
using System.Drawing ;
2019-09-21 19:15:02 +00:00
using osu.Framework.Allocation ;
2020-03-13 06:44:13 +00:00
using osu.Framework.Bindables ;
using osu.Framework.Configuration ;
2019-09-22 19:22:50 +00:00
using osu.Framework.Graphics ;
using osu.Framework.Graphics.Containers ;
using osu.Game.Graphics.UserInterface ;
2019-09-24 10:00:26 +00:00
using osu.Game.Graphics.UserInterfaceV2 ;
2019-09-22 19:45:23 +00:00
using osu.Game.Online.API ;
using osu.Game.Overlays ;
2019-11-11 08:03:50 +00:00
using osu.Game.Rulesets ;
2019-09-21 19:15:02 +00:00
using osu.Game.Tournament.IPC ;
2020-05-16 01:03:10 +00:00
using osu.Game.Tournament.Models ;
2019-09-22 19:22:50 +00:00
using osuTK ;
using osuTK.Graphics ;
2019-09-21 19:15:02 +00:00
2019-09-21 17:10:04 +00:00
namespace osu.Game.Tournament.Screens
{
2019-09-22 19:49:21 +00:00
public class SetupScreen : TournamentScreen , IProvideVideo
2019-09-21 17:10:04 +00:00
{
2019-09-22 19:45:23 +00:00
private FillFlowContainer fillFlow ;
private LoginOverlay loginOverlay ;
2020-05-24 20:24:46 +00:00
private ResolutionSelector resolution ;
2019-09-22 19:45:23 +00:00
2019-09-21 19:15:02 +00:00
[Resolved]
private MatchIPCInfo ipc { get ; set ; }
2020-06-13 13:05:52 +00:00
[Resolved]
private StableInfo stableInfo { get ; set ; }
2019-09-22 19:45:23 +00:00
[Resolved]
private IAPIProvider api { get ; set ; }
2019-11-11 08:03:50 +00:00
[Resolved]
private RulesetStore rulesets { get ; set ; }
2020-05-16 01:03:10 +00:00
[Resolved(canBeNull: true)]
private TournamentSceneManager sceneManager { get ; set ; }
2020-03-13 06:44:13 +00:00
private Bindable < Size > windowSize ;
2019-09-21 19:15:02 +00:00
[BackgroundDependencyLoader]
2020-03-13 06:44:13 +00:00
private void load ( FrameworkConfigManager frameworkConfig )
2019-09-21 19:15:02 +00:00
{
2020-03-13 06:44:13 +00:00
windowSize = frameworkConfig . GetBindable < Size > ( FrameworkSetting . WindowedSize ) ;
2019-09-22 19:45:23 +00:00
InternalChild = fillFlow = new FillFlowContainer
{
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Direction = FillDirection . Vertical ,
Padding = new MarginPadding ( 10 ) ,
Spacing = new Vector2 ( 10 ) ,
} ;
api . LocalUser . BindValueChanged ( _ = > Schedule ( reload ) ) ;
2020-06-13 13:05:52 +00:00
stableInfo . OnStableInfoSaved + = ( ) = > Schedule ( reload ) ;
2019-09-22 19:22:50 +00:00
reload ( ) ;
}
2020-03-13 06:44:13 +00:00
[Resolved]
private Framework . Game game { get ; set ; }
2019-09-22 19:22:50 +00:00
private void reload ( )
{
var fileBasedIpc = ipc as FileBasedIPC ;
2019-09-22 19:45:23 +00:00
fillFlow . Children = new Drawable [ ]
2019-09-22 19:22:50 +00:00
{
new ActionableInfo
{
Label = "Current IPC source" ,
2020-05-17 22:50:08 +00:00
ButtonText = "Change source" ,
2020-06-13 13:05:52 +00:00
Action = ( ) = > sceneManager ? . SetScreen ( new StablePathSelectScreen ( ) ) ,
2020-05-31 15:35:53 +00:00
Value = fileBasedIpc ? . IPCStorage ? . GetFullPath ( string . Empty ) ? ? "Not found" ,
2020-05-16 01:03:10 +00:00
Failing = fileBasedIpc ? . IPCStorage = = null ,
2020-05-17 20:28:54 +00:00
Description = "The osu!stable installation which is currently being used as a data source. If a source is not found, make sure you have created an empty ipc.txt in your stable cutting-edge installation."
2020-05-16 01:03:10 +00:00
} ,
new ActionableInfo
2019-09-22 19:45:23 +00:00
{
2020-11-05 14:40:20 +00:00
Label = "Current user" ,
ButtonText = "Change sign-in" ,
2019-09-22 19:45:23 +00:00
Action = ( ) = >
{
api . Logout ( ) ;
if ( loginOverlay = = null )
{
2019-09-22 19:49:21 +00:00
AddInternal ( loginOverlay = new LoginOverlay
2019-09-22 19:45:23 +00:00
{
Anchor = Anchor . TopRight ,
Origin = Anchor . TopRight ,
} ) ;
}
loginOverlay . State . Value = Visibility . Visible ;
} ,
Value = api ? . LocalUser . Value . Username ,
Failing = api ? . IsLoggedIn ! = true ,
2020-11-05 14:40:20 +00:00
Description = "In order to access the API and display metadata, signing in is required."
2019-11-11 08:03:50 +00:00
} ,
new LabelledDropdown < RulesetInfo >
{
Label = "Ruleset" ,
2020-11-05 14:40:20 +00:00
Description = "Decides what stats are displayed and which ranks are retrieved for players." ,
2019-11-11 08:03:50 +00:00
Items = rulesets . AvailableRulesets ,
Current = LadderInfo . Ruleset ,
} ,
2020-05-24 20:24:46 +00:00
resolution = new ResolutionSelector
2020-03-13 06:44:13 +00:00
{
Label = "Stream area resolution" ,
2020-05-24 20:24:46 +00:00
ButtonText = "Set height" ,
2020-05-25 18:11:00 +00:00
Action = height = >
2020-03-13 06:44:13 +00:00
{
2020-05-25 18:11:00 +00:00
windowSize . Value = new Size ( ( int ) ( height * aspect_ratio / TournamentSceneManager . STREAM_AREA_WIDTH * TournamentSceneManager . REQUIRED_WIDTH ) , height ) ;
2020-03-13 06:44:13 +00:00
}
2020-03-23 02:47:24 +00:00
} ,
2019-09-22 19:22:50 +00:00
} ;
}
2020-05-22 17:25:05 +00:00
private const float aspect_ratio = 16f / 9f ;
2020-03-13 06:44:13 +00:00
protected override void Update ( )
{
base . Update ( ) ;
resolution . Value = $"{ScreenSpaceDrawQuad.Width:N0}x{ScreenSpaceDrawQuad.Height:N0}" ;
}
2019-11-12 02:04:49 +00:00
public class LabelledDropdown < T > : LabelledComponent < OsuDropdown < T > , T >
{
public LabelledDropdown ( )
: base ( true )
{
}
public IEnumerable < T > Items
{
get = > Component . Items ;
set = > Component . Items = value ;
}
protected override OsuDropdown < T > CreateComponent ( ) = > new OsuDropdown < T >
{
RelativeSizeAxes = Axes . X ,
Width = 0.5f ,
} ;
}
2019-10-28 06:33:08 +00:00
private class ActionableInfo : LabelledDrawable < Drawable >
2019-09-22 19:22:50 +00:00
{
private OsuButton button ;
public ActionableInfo ( )
: base ( true )
{
}
public string ButtonText
{
set = > button . Text = value ;
}
public string Value
{
set = > valueText . Text = value ;
}
public bool Failing
{
set = > valueText . Colour = value ? Color4 . Red : Color4 . White ;
}
public Action Action ;
2020-03-03 10:14:44 +00:00
private TournamentSpriteText valueText ;
2020-05-24 20:24:46 +00:00
protected FillFlowContainer FlowContainer ;
2019-09-22 19:22:50 +00:00
protected override Drawable CreateComponent ( ) = > new Container
2019-09-21 19:15:02 +00:00
{
2019-09-22 19:22:50 +00:00
AutoSizeAxes = Axes . Y ,
RelativeSizeAxes = Axes . X ,
Children = new Drawable [ ]
{
2020-03-03 10:14:44 +00:00
valueText = new TournamentSpriteText
2019-09-22 19:22:50 +00:00
{
Anchor = Anchor . CentreLeft ,
Origin = Anchor . CentreLeft ,
} ,
2020-05-24 20:24:46 +00:00
FlowContainer = new FillFlowContainer
2019-09-22 19:22:50 +00:00
{
Anchor = Anchor . CentreRight ,
Origin = Anchor . CentreRight ,
2020-05-24 20:24:46 +00:00
AutoSizeAxes = Axes . Both ,
Spacing = new Vector2 ( 10 , 0 ) ,
Children = new Drawable [ ]
{
2020-05-24 22:55:10 +00:00
button = new TriangleButton
2020-05-24 20:24:46 +00:00
{
2020-06-02 10:29:59 +00:00
Size = new Vector2 ( 100 , 40 ) ,
2020-05-24 20:24:46 +00:00
Action = ( ) = > Action ? . Invoke ( )
}
}
}
2019-09-22 19:22:50 +00:00
}
} ;
2019-09-21 19:15:02 +00:00
}
2020-05-22 17:25:05 +00:00
2020-05-24 20:24:46 +00:00
private class ResolutionSelector : ActionableInfo
2020-05-22 17:25:05 +00:00
{
2020-05-25 18:20:26 +00:00
private const int minimum_window_height = 480 ;
2020-06-02 10:29:22 +00:00
private const int maximum_window_height = 2160 ;
2020-05-22 17:25:05 +00:00
public new Action < int > Action ;
private OsuNumberBox numberBox ;
2020-05-24 20:24:46 +00:00
protected override Drawable CreateComponent ( )
2020-05-22 17:25:05 +00:00
{
2020-05-24 20:24:46 +00:00
var drawable = base . CreateComponent ( ) ;
2020-05-24 22:55:10 +00:00
FlowContainer . Insert ( - 1 , numberBox = new OsuNumberBox
2020-05-22 17:25:05 +00:00
{
2020-06-02 10:29:22 +00:00
Text = "1080" ,
2020-05-24 20:24:46 +00:00
Width = 100
} ) ;
2020-05-22 17:25:05 +00:00
2020-05-24 20:24:46 +00:00
base . Action = ( ) = >
2020-05-22 17:25:05 +00:00
{
2020-05-25 18:18:17 +00:00
if ( string . IsNullOrEmpty ( numberBox . Text ) )
return ;
// box contains text
if ( ! int . TryParse ( numberBox . Text , out var number ) )
2020-05-22 17:25:05 +00:00
{
2020-05-25 18:18:17 +00:00
// at this point, the only reason we can arrive here is if the input number was too big to parse into an int
// so clamp to max allowed value
2020-05-25 18:20:26 +00:00
number = maximum_window_height ;
2020-05-25 18:18:17 +00:00
}
else
{
2020-05-25 18:20:26 +00:00
number = Math . Clamp ( number , minimum_window_height , maximum_window_height ) ;
2020-05-25 18:18:17 +00:00
}
2020-05-24 20:24:46 +00:00
2020-05-25 18:18:17 +00:00
// in case number got clamped, reset number in numberBox
numberBox . Text = number . ToString ( ) ;
2020-05-24 20:24:46 +00:00
2020-05-25 18:18:17 +00:00
Action ? . Invoke ( number ) ;
2020-05-24 20:24:46 +00:00
} ;
return drawable ;
}
2020-05-22 17:25:05 +00:00
}
2019-09-21 17:10:04 +00:00
}
}