1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 13:07:24 +08:00
osu-lazer/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
Dean Herbert 6929be49b7 Change condition for exclusive fullscreen notice to only show when using the correct renderer
This avoids the notice showing when running on windows, but using the
newer renderers (where the underlying logic hasn't been tested properly
and can result in false-positives).

Supersedes https://github.com/ppy/osu-framework/pull/5759 as a more
correct implementation.
2023-04-28 22:36:30 +09:00

363 lines
14 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.Drawing;
using System.Linq;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Framework.Platform;
using osu.Framework.Platform.Windows;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Settings.Sections.Graphics
{
public partial class LayoutSettings : SettingsSubsection
{
protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader;
private FillFlowContainer<SettingsSlider<float>> scalingSettings = null!;
private readonly Bindable<Display> currentDisplay = new Bindable<Display>();
private Bindable<ScalingMode> scalingMode = null!;
private Bindable<Size> sizeFullscreen = null!;
private readonly BindableList<Size> resolutions = new BindableList<Size>(new[] { new Size(9999, 9999) });
private readonly IBindable<FullscreenCapability> fullscreenCapability = new Bindable<FullscreenCapability>(FullscreenCapability.Capable);
[Resolved]
private OsuGameBase game { get; set; } = null!;
[Resolved]
private GameHost host { get; set; } = null!;
private IWindow? window;
private SettingsDropdown<Size> resolutionDropdown = null!;
private SettingsDropdown<Display> displayDropdown = null!;
private SettingsDropdown<WindowMode> windowModeDropdown = null!;
private SettingsCheckbox safeAreaConsiderationsCheckbox = null!;
private Bindable<float> scalingPositionX = null!;
private Bindable<float> scalingPositionY = null!;
private Bindable<float> scalingSizeX = null!;
private Bindable<float> scalingSizeY = null!;
private const int transition_duration = 400;
[BackgroundDependencyLoader]
private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, GameHost host)
{
window = host.Window;
scalingMode = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling);
sizeFullscreen = config.GetBindable<Size>(FrameworkSetting.SizeFullscreen);
scalingSizeX = osuConfig.GetBindable<float>(OsuSetting.ScalingSizeX);
scalingSizeY = osuConfig.GetBindable<float>(OsuSetting.ScalingSizeY);
scalingPositionX = osuConfig.GetBindable<float>(OsuSetting.ScalingPositionX);
scalingPositionY = osuConfig.GetBindable<float>(OsuSetting.ScalingPositionY);
if (window != null)
{
currentDisplay.BindTo(window.CurrentDisplayBindable);
window.DisplaysChanged += onDisplaysChanged;
}
if (host.Renderer is IWindowsRenderer windowsRenderer)
fullscreenCapability.BindTo(windowsRenderer.FullscreenCapability);
Children = new Drawable[]
{
windowModeDropdown = new SettingsDropdown<WindowMode>
{
LabelText = GraphicsSettingsStrings.ScreenMode,
Items = window?.SupportedWindowModes,
CanBeShown = { Value = window?.SupportedWindowModes.Count() > 1 },
Current = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode),
},
displayDropdown = new DisplaySettingsDropdown
{
LabelText = GraphicsSettingsStrings.Display,
Items = window?.Displays,
Current = currentDisplay,
},
resolutionDropdown = new ResolutionSettingsDropdown
{
LabelText = GraphicsSettingsStrings.Resolution,
ShowsDefaultIndicator = false,
ItemSource = resolutions,
Current = sizeFullscreen
},
safeAreaConsiderationsCheckbox = new SettingsCheckbox
{
LabelText = "Shrink game to avoid cameras and notches",
Current = osuConfig.GetBindable<bool>(OsuSetting.SafeAreaConsiderations),
},
new SettingsSlider<float, UIScaleSlider>
{
LabelText = GraphicsSettingsStrings.UIScaling,
TransferValueOnCommit = true,
Current = osuConfig.GetBindable<float>(OsuSetting.UIScale),
KeyboardStep = 0.01f,
Keywords = new[] { "scale", "letterbox" },
},
new SettingsEnumDropdown<ScalingMode>
{
LabelText = GraphicsSettingsStrings.ScreenScaling,
Current = osuConfig.GetBindable<ScalingMode>(OsuSetting.Scaling),
Keywords = new[] { "scale", "letterbox" },
},
scalingSettings = new FillFlowContainer<SettingsSlider<float>>
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Masking = true,
Children = new[]
{
new SettingsSlider<float>
{
LabelText = GraphicsSettingsStrings.HorizontalPosition,
Keywords = new[] { "screen", "scaling" },
Current = scalingPositionX,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = GraphicsSettingsStrings.VerticalPosition,
Keywords = new[] { "screen", "scaling" },
Current = scalingPositionY,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = GraphicsSettingsStrings.HorizontalScale,
Keywords = new[] { "screen", "scaling" },
Current = scalingSizeX,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = GraphicsSettingsStrings.VerticalScale,
Keywords = new[] { "screen", "scaling" },
Current = scalingSizeY,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
}
},
};
fullscreenCapability.BindValueChanged(_ => Schedule(updateScreenModeWarning), true);
}
protected override void LoadComplete()
{
base.LoadComplete();
scalingSettings.ForEach(s => bindPreviewEvent(s.Current));
windowModeDropdown.Current.BindValueChanged(_ =>
{
updateDisplaySettingsVisibility();
updateScreenModeWarning();
}, true);
currentDisplay.BindValueChanged(display => Schedule(() =>
{
resolutions.RemoveRange(1, resolutions.Count - 1);
if (display.NewValue != null)
{
resolutions.AddRange(display.NewValue.DisplayModes
.Where(m => m.Size.Width >= 800 && m.Size.Height >= 600)
.OrderByDescending(m => Math.Max(m.Size.Height, m.Size.Width))
.Select(m => m.Size)
.Distinct());
}
updateDisplaySettingsVisibility();
}), true);
scalingMode.BindValueChanged(_ =>
{
scalingSettings.ClearTransforms();
scalingSettings.AutoSizeDuration = transition_duration;
scalingSettings.AutoSizeEasing = Easing.OutQuint;
updateScalingModeVisibility();
});
// initial update bypasses transforms
updateScalingModeVisibility();
void updateScalingModeVisibility()
{
if (scalingMode.Value == ScalingMode.Off)
scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None;
scalingSettings.ForEach(s =>
{
s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything;
s.CanBeShown.Value = scalingMode.Value != ScalingMode.Off;
});
}
}
private void onDisplaysChanged(IEnumerable<Display> displays)
{
Scheduler.AddOnce(d =>
{
displayDropdown.Items = d;
updateDisplaySettingsVisibility();
}, displays);
}
private void updateDisplaySettingsVisibility()
{
resolutionDropdown.CanBeShown.Value = resolutions.Count > 1 && windowModeDropdown.Current.Value == WindowMode.Fullscreen;
displayDropdown.CanBeShown.Value = displayDropdown.Items.Count() > 1;
safeAreaConsiderationsCheckbox.CanBeShown.Value = host.Window?.SafeAreaPadding.Value.Total != Vector2.Zero;
}
private void updateScreenModeWarning()
{
if (RuntimeInfo.OS == RuntimeInfo.Platform.macOS)
{
if (windowModeDropdown.Current.Value == WindowMode.Fullscreen)
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.FullscreenMacOSNote, true);
else
windowModeDropdown.ClearNoticeText();
return;
}
if (windowModeDropdown.Current.Value != WindowMode.Fullscreen)
{
windowModeDropdown.SetNoticeText(GraphicsSettingsStrings.NotFullscreenNote, true);
return;
}
if (host.Renderer is IWindowsRenderer)
{
switch (fullscreenCapability.Value)
{
case FullscreenCapability.Unknown:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.CheckingForFullscreenCapabilities, true);
break;
case FullscreenCapability.Capable:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.OsuIsRunningExclusiveFullscreen);
break;
case FullscreenCapability.Incapable:
windowModeDropdown.SetNoticeText(LayoutSettingsStrings.UnableToRunExclusiveFullscreen, true);
break;
}
}
else
{
// We can only detect exclusive fullscreen status on windows currently.
windowModeDropdown.ClearNoticeText();
}
}
private void bindPreviewEvent(Bindable<float> bindable)
{
bindable.ValueChanged += _ =>
{
switch (scalingMode.Value)
{
case ScalingMode.Gameplay:
showPreview();
break;
}
};
}
private Drawable? preview;
private void showPreview()
{
if (preview?.IsAlive != true)
game.Add(preview = new ScalingPreview());
preview.FadeOutFromOne(1500);
preview.Expire();
}
protected override void Dispose(bool isDisposing)
{
if (window != null)
window.DisplaysChanged -= onDisplaysChanged;
base.Dispose(isDisposing);
}
private partial class ScalingPreview : ScalingContainer
{
public ScalingPreview()
{
Child = new Box
{
Colour = Color4.White,
RelativeSizeAxes = Axes.Both,
Alpha = 0.5f,
};
}
}
private partial class UIScaleSlider : RoundedSliderBar<float>
{
public override LocalisableString TooltipText => base.TooltipText + "x";
}
private partial class DisplaySettingsDropdown : SettingsDropdown<Display>
{
protected override OsuDropdown<Display> CreateDropdown() => new DisplaySettingsDropdownControl();
private partial class DisplaySettingsDropdownControl : DropdownControl
{
protected override LocalisableString GenerateItemText(Display item)
{
return $"{item.Index}: {item.Name} ({item.Bounds.Width}x{item.Bounds.Height})";
}
}
}
private partial class ResolutionSettingsDropdown : SettingsDropdown<Size>
{
protected override OsuDropdown<Size> CreateDropdown() => new ResolutionDropdownControl();
private partial class ResolutionDropdownControl : DropdownControl
{
protected override LocalisableString GenerateItemText(Size item)
{
if (item == new Size(9999, 9999))
return CommonStrings.Default;
return $"{item.Width}x{item.Height}";
}
}
}
}
}