mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 05:39:53 +08:00
b76a7e1bb6
This commit rearranges the contents of `ShearedButtons` to be more independent of each other in regards to sizing. Thanks to that, the custom logic related to enabling autosizing is no longer necessary. Witdh and height are no longer set via the constructor, and can be freely configured using the initializer syntax. Additionally, this allows the button to use relative sizing without having to resort to any hackery with `Size` (this will come in handy for me when implementing the new footer on multiplayer screens). Given that most of the `ShearedButton`s currently in use set their width explicitly, I did not set `AutoSizeAxes = Axes.X` like it would be by default previously. Instead it is set on the only two such buttons (show converts/selected mods on ssv2). I suppose it might be a good idea to have it set that by default if no `Width` is specified, as right now it'll just not show anything. Also I've set the margin on the text field by default in all cases instead of only when autosizing like how it was previously, since otherwise it would be a pain to set that on each button instance when needed. I've checked all affected components and could not find any text overflowing issues that this could cause. --------- Co-authored-by: Dean Herbert <pe@ppy.sh>
289 lines
9.1 KiB
C#
289 lines
9.1 KiB
C#
// 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.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using osu.Framework.Allocation;
|
|
using osu.Framework.Extensions;
|
|
using osu.Framework.Graphics;
|
|
using osu.Framework.Graphics.Containers;
|
|
using osu.Framework.Graphics.Cursor;
|
|
using osu.Framework.Graphics.Shapes;
|
|
using osu.Framework.Input.Events;
|
|
using osu.Framework.Localisation;
|
|
using osu.Framework.Screens;
|
|
using osu.Framework.Threading;
|
|
using osu.Game.Graphics;
|
|
using osu.Game.Graphics.UserInterface;
|
|
using osu.Game.Input.Bindings;
|
|
using osu.Game.Localisation;
|
|
using osu.Game.Overlays.Mods;
|
|
using osu.Game.Screens.Footer;
|
|
|
|
namespace osu.Game.Overlays
|
|
{
|
|
public partial class WizardOverlay : ShearedOverlayContainer
|
|
{
|
|
private ScreenStack? stack;
|
|
|
|
public ShearedButton? NextButton => DisplayedFooterContent?.NextButton;
|
|
|
|
protected int? CurrentStepIndex { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The currently displayed screen, if any.
|
|
/// </summary>
|
|
public WizardScreen? CurrentScreen => (WizardScreen?)stack?.CurrentScreen;
|
|
|
|
private readonly List<Type> steps = new List<Type>();
|
|
|
|
private Container screenContent = null!;
|
|
|
|
private Container content = null!;
|
|
|
|
private LoadingSpinner loading = null!;
|
|
private ScheduledDelegate? loadingShowDelegate;
|
|
|
|
public bool Completed { get; private set; }
|
|
|
|
protected WizardOverlay(OverlayColourScheme scheme)
|
|
: base(scheme)
|
|
{
|
|
}
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load()
|
|
{
|
|
MainAreaContent.AddRange(new Drawable[]
|
|
{
|
|
content = new PopoverContainer
|
|
{
|
|
Anchor = Anchor.Centre,
|
|
Origin = Anchor.Centre,
|
|
RelativeSizeAxes = Axes.Both,
|
|
Padding = new MarginPadding { Bottom = 20 },
|
|
Child = new GridContainer
|
|
{
|
|
Anchor = Anchor.Centre,
|
|
Origin = Anchor.Centre,
|
|
RelativeSizeAxes = Axes.Both,
|
|
ColumnDimensions = new[]
|
|
{
|
|
new Dimension(),
|
|
new Dimension(minSize: 640, maxSize: 800),
|
|
new Dimension(),
|
|
},
|
|
Content = new[]
|
|
{
|
|
new[]
|
|
{
|
|
Empty(),
|
|
new InputBlockingContainer
|
|
{
|
|
Masking = true,
|
|
CornerRadius = 14,
|
|
RelativeSizeAxes = Axes.Both,
|
|
Children = new Drawable[]
|
|
{
|
|
new Box
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Colour = ColourProvider.Background6,
|
|
},
|
|
loading = new LoadingSpinner(),
|
|
new Container
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
Padding = new MarginPadding { Vertical = 20 },
|
|
Child = screenContent = new Container { RelativeSizeAxes = Axes.Both, },
|
|
},
|
|
},
|
|
},
|
|
Empty(),
|
|
},
|
|
}
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
[Resolved]
|
|
private ScreenFooter footer { get; set; } = null!;
|
|
|
|
public new WizardFooterContent? DisplayedFooterContent => base.DisplayedFooterContent as WizardFooterContent;
|
|
|
|
public override VisibilityContainer CreateFooterContent()
|
|
{
|
|
var footerContent = new WizardFooterContent
|
|
{
|
|
ShowNextStep = ShowNextStep,
|
|
};
|
|
|
|
footerContent.OnLoadComplete += _ => updateButtons();
|
|
return footerContent;
|
|
}
|
|
|
|
public override bool OnBackButton()
|
|
{
|
|
if (CurrentStepIndex == 0)
|
|
return false;
|
|
|
|
Debug.Assert(stack != null);
|
|
|
|
stack.CurrentScreen.Exit();
|
|
CurrentStepIndex--;
|
|
|
|
updateButtons();
|
|
return true;
|
|
}
|
|
|
|
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
|
{
|
|
if (!e.Repeat)
|
|
{
|
|
switch (e.Action)
|
|
{
|
|
case GlobalAction.Select:
|
|
DisplayedFooterContent?.NextButton.TriggerClick();
|
|
return true;
|
|
|
|
case GlobalAction.Back:
|
|
footer.BackButton.TriggerClick();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return base.OnPressed(e);
|
|
}
|
|
|
|
protected override void PopIn()
|
|
{
|
|
base.PopIn();
|
|
|
|
content.ScaleTo(0.99f)
|
|
.ScaleTo(1, 400, Easing.OutQuint);
|
|
|
|
if (CurrentStepIndex == null)
|
|
showFirstStep();
|
|
}
|
|
|
|
protected override void PopOut()
|
|
{
|
|
base.PopOut();
|
|
|
|
content.ScaleTo(0.99f, 400, Easing.OutQuint);
|
|
|
|
if (CurrentStepIndex == null)
|
|
{
|
|
stack?.FadeOut(100)
|
|
.Expire();
|
|
}
|
|
}
|
|
|
|
protected void AddStep<T>()
|
|
where T : WizardScreen
|
|
{
|
|
steps.Add(typeof(T));
|
|
}
|
|
|
|
private void showFirstStep()
|
|
{
|
|
Debug.Assert(CurrentStepIndex == null);
|
|
|
|
screenContent.Child = stack = new ScreenStack
|
|
{
|
|
RelativeSizeAxes = Axes.Both,
|
|
};
|
|
|
|
CurrentStepIndex = -1;
|
|
ShowNextStep();
|
|
}
|
|
|
|
protected virtual void ShowNextStep()
|
|
{
|
|
Debug.Assert(CurrentStepIndex != null);
|
|
Debug.Assert(stack != null);
|
|
|
|
CurrentStepIndex++;
|
|
|
|
if (CurrentStepIndex < steps.Count)
|
|
{
|
|
var nextScreen = (Screen)Activator.CreateInstance(steps[CurrentStepIndex.Value])!;
|
|
|
|
loadingShowDelegate = Scheduler.AddDelayed(() => loading.Show(), 200);
|
|
nextScreen.OnLoadComplete += _ =>
|
|
{
|
|
loadingShowDelegate?.Cancel();
|
|
loading.Hide();
|
|
};
|
|
|
|
stack.Push(nextScreen);
|
|
}
|
|
else
|
|
{
|
|
CurrentStepIndex = null;
|
|
Completed = true;
|
|
Hide();
|
|
}
|
|
|
|
updateButtons();
|
|
}
|
|
|
|
private void updateButtons() => DisplayedFooterContent?.UpdateButtons(CurrentStepIndex, CurrentScreen, steps);
|
|
|
|
public partial class WizardFooterContent : VisibilityContainer
|
|
{
|
|
public ShearedButton NextButton { get; private set; } = null!;
|
|
|
|
public Action? ShowNextStep;
|
|
|
|
[BackgroundDependencyLoader]
|
|
private void load(OverlayColourProvider colourProvider)
|
|
{
|
|
RelativeSizeAxes = Axes.Both;
|
|
|
|
Padding = new MarginPadding { Right = OsuGame.SCREEN_EDGE_MARGIN };
|
|
|
|
InternalChild = NextButton = new ShearedButton
|
|
{
|
|
RelativeSizeAxes = Axes.X,
|
|
Text = FirstRunSetupOverlayStrings.GetStarted,
|
|
DarkerColour = colourProvider.Colour3,
|
|
LighterColour = colourProvider.Colour2,
|
|
Action = () => ShowNextStep?.Invoke(),
|
|
};
|
|
}
|
|
|
|
public void UpdateButtons(int? currentStep, WizardScreen? currentScreen, IReadOnlyList<Type> steps)
|
|
{
|
|
NextButton.Enabled.Value = currentStep != null;
|
|
|
|
if (currentStep == null)
|
|
return;
|
|
|
|
bool isLastStep = currentStep == steps.Count - 1;
|
|
|
|
if (currentScreen?.NextStepText != null)
|
|
NextButton.Text = currentScreen.NextStepText.Value;
|
|
else
|
|
{
|
|
NextButton.Text = isLastStep
|
|
? CommonStrings.Finish
|
|
: LocalisableString.Interpolate($@"{CommonStrings.Next} ({steps[currentStep.Value + 1].GetLocalisableDescription()})");
|
|
}
|
|
}
|
|
|
|
protected override void PopIn()
|
|
{
|
|
this.FadeIn();
|
|
}
|
|
|
|
protected override void PopOut()
|
|
{
|
|
this.Delay(400).FadeOut();
|
|
}
|
|
}
|
|
}
|
|
}
|