1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 10:12:54 +08:00

Merge pull request #16772 from peppy/mvp-safe-area-support

This commit is contained in:
Salman Ahmed 2022-02-04 17:28:32 +03:00 committed by GitHub
commit 0f15cf07ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 159 additions and 17 deletions

View File

@ -0,0 +1,115 @@
// 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 NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Overlays.Settings;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneSafeAreaHandling : OsuGameTestScene
{
private SafeAreaDefiningContainer safeAreaContainer;
private static BindableSafeArea safeArea;
private readonly Bindable<float> safeAreaPaddingTop = new BindableFloat { MinValue = 0, MaxValue = 200 };
private readonly Bindable<float> safeAreaPaddingBottom = new BindableFloat { MinValue = 0, MaxValue = 200 };
private readonly Bindable<float> safeAreaPaddingLeft = new BindableFloat { MinValue = 0, MaxValue = 200 };
private readonly Bindable<float> safeAreaPaddingRight = new BindableFloat { MinValue = 0, MaxValue = 200 };
protected override void LoadComplete()
{
base.LoadComplete();
// Usually this would be placed between the host and the game, but that's a bit of a pain to do with the test scene hierarchy.
// Add is required for the container to get a size (and give out correct metrics to the usages in SafeAreaContainer).
Add(safeAreaContainer = new SafeAreaDefiningContainer(safeArea = new BindableSafeArea())
{
RelativeSizeAxes = Axes.Both
});
// Cache is required for the test game to see the safe area.
Dependencies.CacheAs<ISafeArea>(safeAreaContainer);
}
public override void SetUpSteps()
{
AddStep("Add adjust controls", () =>
{
Add(new Container
{
Depth = float.MinValue,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
Alpha = 0.8f,
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
Width = 400,
Children = new Drawable[]
{
new SettingsSlider<float>
{
Current = safeAreaPaddingTop,
LabelText = "Top"
},
new SettingsSlider<float>
{
Current = safeAreaPaddingBottom,
LabelText = "Bottom"
},
new SettingsSlider<float>
{
Current = safeAreaPaddingLeft,
LabelText = "Left"
},
new SettingsSlider<float>
{
Current = safeAreaPaddingRight,
LabelText = "Right"
},
}
}
}
});
safeAreaPaddingTop.BindValueChanged(_ => updateSafeArea());
safeAreaPaddingBottom.BindValueChanged(_ => updateSafeArea());
safeAreaPaddingLeft.BindValueChanged(_ => updateSafeArea());
safeAreaPaddingRight.BindValueChanged(_ => updateSafeArea());
});
base.SetUpSteps();
}
private void updateSafeArea()
{
safeArea.Value = new MarginPadding
{
Top = safeAreaPaddingTop.Value,
Bottom = safeAreaPaddingBottom.Value,
Left = safeAreaPaddingLeft.Value,
Right = safeAreaPaddingRight.Value,
};
}
[Test]
public void TestSafeArea()
{
}
}
}

View File

@ -23,6 +23,8 @@ namespace osu.Game.Graphics.Containers
private Bindable<float> posX;
private Bindable<float> posY;
private Bindable<MarginPadding> safeAreaPadding;
private readonly ScalingMode? targetMode;
private Bindable<ScalingMode> scalingMode;
@ -50,7 +52,7 @@ namespace osu.Game.Graphics.Containers
return;
allowScaling = value;
if (IsLoaded) updateSize();
if (IsLoaded) Scheduler.AddOnce(updateSize);
}
}
@ -102,22 +104,25 @@ namespace osu.Game.Graphics.Containers
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
private void load(OsuConfigManager config, ISafeArea safeArea)
{
scalingMode = config.GetBindable<ScalingMode>(OsuSetting.Scaling);
scalingMode.ValueChanged += _ => updateSize();
scalingMode.ValueChanged += _ => Scheduler.AddOnce(updateSize);
sizeX = config.GetBindable<float>(OsuSetting.ScalingSizeX);
sizeX.ValueChanged += _ => updateSize();
sizeX.ValueChanged += _ => Scheduler.AddOnce(updateSize);
sizeY = config.GetBindable<float>(OsuSetting.ScalingSizeY);
sizeY.ValueChanged += _ => updateSize();
sizeY.ValueChanged += _ => Scheduler.AddOnce(updateSize);
posX = config.GetBindable<float>(OsuSetting.ScalingPositionX);
posX.ValueChanged += _ => updateSize();
posX.ValueChanged += _ => Scheduler.AddOnce(updateSize);
posY = config.GetBindable<float>(OsuSetting.ScalingPositionY);
posY.ValueChanged += _ => updateSize();
posY.ValueChanged += _ => Scheduler.AddOnce(updateSize);
safeAreaPadding = safeArea.SafeAreaPadding.GetBoundCopy();
safeAreaPadding.BindValueChanged(_ => Scheduler.AddOnce(updateSize));
}
protected override void LoadComplete()
@ -161,7 +166,10 @@ namespace osu.Game.Graphics.Containers
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;
bool requiresMasking = (scaling && targetSize != 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);
if (requiresMasking)
sizableContainer.Masking = true;

View File

@ -89,6 +89,12 @@ namespace osu.Game
}
}
/// <summary>
/// The <see cref="Edges"/> that the game should be drawn over at a top level.
/// Defaults to <see cref="Edges.None"/>.
/// </summary>
protected virtual Edges SafeAreaOverrideEdges => Edges.None;
protected OsuConfigManager LocalConfig { get; private set; }
protected SessionStatics SessionStatics { get; private set; }
@ -299,16 +305,23 @@ namespace osu.Game
GlobalActionContainer globalBindings;
var mainContent = new Drawable[]
base.Content.Add(new SafeAreaContainer
{
MenuCursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both },
// to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
globalBindings = new GlobalActionContainer(this)
};
MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both };
base.Content.Add(CreateScalingContainer().WithChildren(mainContent));
SafeAreaOverrideEdges = SafeAreaOverrideEdges,
RelativeSizeAxes = Axes.Both,
Child = CreateScalingContainer().WithChildren(new Drawable[]
{
(MenuCursorContainer = new MenuCursorContainer
{
RelativeSizeAxes = Axes.Both
}).WithChild(content = new OsuTooltipContainer(MenuCursorContainer.Cursor)
{
RelativeSizeAxes = Axes.Both
}),
// to avoid positional input being blocked by children, ensure the GlobalActionContainer is above everything.
globalBindings = new GlobalActionContainer(this)
})
});
KeyBindingStore = new RealmKeyBindingStore(realm, keyCombinationProvider);
KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets);

View File

@ -3,6 +3,7 @@
using System;
using Foundation;
using osu.Framework.Graphics;
using osu.Game;
using osu.Game.Updater;
using osu.Game.Utils;
@ -18,6 +19,11 @@ namespace osu.iOS
protected override BatteryInfo CreateBatteryInfo() => new IOSBatteryInfo();
protected override Edges SafeAreaOverrideEdges =>
// iOS shows a home indicator at the bottom, and adds a safe area to account for this.
// Because we have the home indicator (mostly) hidden we don't really care about drawing in this region.
Edges.Bottom;
private class IOSBatteryInfo : BatteryInfo
{
public override double ChargeLevel => Battery.ChargeLevel;