1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 09:02:55 +08:00

Merge pull request #17049 from peppy/scaling-container-better-custom-override

Apply scaling container transforms at a single point to improve transitions
This commit is contained in:
Dean Herbert 2022-03-04 11:38:23 +09:00 committed by GitHub
commit 7be2d94b6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 40 deletions

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Screens;
using osu.Game.Configuration;
using osu.Game.Screens;
@ -38,24 +39,24 @@ namespace osu.Game.Graphics.Containers
private BackgroundScreenStack backgroundStack;
private bool allowScaling = true;
private RectangleF? customRect;
private bool customRectIsRelativePosition;
/// <summary>
/// Whether user scaling preferences should be applied. Enabled by default.
/// Set a custom position and scale which overrides any user specification.
/// </summary>
public bool AllowScaling
/// <param name="rect">A rectangle with positional and sizing information for this container to conform to. <c>null</c> will clear the custom rect and revert to user settings.</param>
/// <param name="relativePosition">Whether the position portion of the provided rect is in relative coordinate space or not.</param>
public void SetCustomRect(RectangleF? rect, bool relativePosition = false)
{
get => allowScaling;
set
{
if (value == allowScaling)
return;
customRect = rect;
customRectIsRelativePosition = relativePosition;
allowScaling = value;
if (IsLoaded) Scheduler.AddOnce(updateSize);
}
if (IsLoaded) Scheduler.AddOnce(updateSize);
}
private const float corner_radius = 10;
/// <summary>
/// Create a new instance.
/// </summary>
@ -69,7 +70,7 @@ namespace osu.Game.Graphics.Containers
{
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Both,
CornerRadius = 10,
CornerRadius = corner_radius,
Child = content = new ScalingDrawSizePreservingFillContainer(targetMode != ScalingMode.Gameplay)
};
}
@ -137,7 +138,7 @@ namespace osu.Game.Graphics.Containers
private void updateSize()
{
const float fade_time = 500;
const float duration = 500;
if (targetMode == ScalingMode.Everything)
{
@ -156,17 +157,31 @@ namespace osu.Game.Graphics.Containers
backgroundStack.Push(new ScalingBackgroundScreen());
}
backgroundStack.FadeIn(fade_time);
backgroundStack.FadeIn(duration);
}
else
backgroundStack?.FadeOut(fade_time);
backgroundStack?.FadeOut(duration);
}
bool scaling = AllowScaling && (targetMode == null || scalingMode.Value == targetMode);
RectangleF targetRect = new RectangleF(Vector2.Zero, Vector2.One);
var targetSize = scaling ? new Vector2(sizeX.Value, sizeY.Value) : Vector2.One;
var targetPosition = scaling ? new Vector2(posX.Value, posY.Value) * (Vector2.One - targetSize) : Vector2.Zero;
bool requiresMasking = (scaling && targetSize != Vector2.One)
if (customRect != null)
{
sizableContainer.RelativePositionAxes = customRectIsRelativePosition ? Axes.Both : Axes.None;
targetRect = customRect.Value;
}
else if (targetMode == null || scalingMode.Value == targetMode)
{
sizableContainer.RelativePositionAxes = Axes.Both;
Vector2 scale = new Vector2(sizeX.Value, sizeY.Value);
Vector2 pos = new Vector2(posX.Value, posY.Value) * (Vector2.One - scale);
targetRect = new RectangleF(pos, scale);
}
bool requiresMasking = targetRect.Size != Vector2.One
// For the top level scaling container, for now we apply masking if safe areas are in use.
// In the future this can likely be removed as more of the actual UI supports overflowing into the safe areas.
|| (targetMode == ScalingMode.Everything && safeAreaPadding.Value.Total != Vector2.Zero);
@ -174,8 +189,14 @@ namespace osu.Game.Graphics.Containers
if (requiresMasking)
sizableContainer.Masking = true;
sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart);
sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
sizableContainer.MoveTo(targetRect.Location, duration, Easing.OutQuart);
sizableContainer.ResizeTo(targetRect.Size, duration, Easing.OutQuart);
// Of note, this will not work great in the case of nested ScalingContainers where multiple are applying corner radius.
// Masking and corner radius should likely only be applied at one point in the full game stack to fix this.
// An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything".
sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, duration, requiresMasking ? Easing.OutQuart : Easing.None)
.OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
}
private class ScalingBackgroundScreen : BackgroundScreenDefault

View File

@ -23,6 +23,8 @@ namespace osu.Game.Skinning.Editor
{
public class SkinComponentToolbox : ScrollingToolboxGroup
{
public const float WIDTH = 200;
public Action<Type> RequestPlacement;
private const float component_display_scale = 0.8f;
@ -41,7 +43,7 @@ namespace osu.Game.Skinning.Editor
: base("Components", height)
{
RelativeSizeAxes = Axes.None;
Width = 200;
Width = WIDTH;
}
[BackgroundDependencyLoader]

View File

@ -5,6 +5,7 @@ using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
@ -100,30 +101,14 @@ namespace osu.Game.Skinning.Editor
{
if (visibility.NewValue == Visibility.Visible)
{
updateMasking();
target.AllowScaling = false;
target.RelativePositionAxes = Axes.Both;
target.ScaleTo(VISIBLE_TARGET_SCALE, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
target.MoveToX(0.095f, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
target.SetCustomRect(new RectangleF(0.18f, 0.1f, VISIBLE_TARGET_SCALE, VISIBLE_TARGET_SCALE), true);
}
else
{
target.AllowScaling = true;
target.ScaleTo(1, SkinEditor.TRANSITION_DURATION, Easing.OutQuint).OnComplete(_ => updateMasking());
target.MoveToX(0f, SkinEditor.TRANSITION_DURATION, Easing.OutQuint);
target.SetCustomRect(null);
}
}
private void updateMasking()
{
if (skinEditor == null)
return;
target.Masking = skinEditor.State.Value == Visibility.Visible;
}
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
{
}