diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 0534fd9253..6ad5b2070e 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
@@ -9,6 +10,7 @@ using Newtonsoft.Json;
using osu.Game.Database;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
+using osu.Game.Scoring;
namespace osu.Game.Beatmaps
{
@@ -112,6 +114,11 @@ namespace osu.Game.Beatmaps
[JsonProperty("difficulty_rating")]
public double StarDifficulty { get; set; }
+ ///
+ /// Currently only populated for beatmap deletion. Use to query scores.
+ ///
+ public List Scores { get; set; }
+
public override string ToString() => $"{Metadata} [{Version}]";
public bool Equals(BeatmapInfo other)
diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs
index 5bdc42cdf3..6817c0653d 100644
--- a/osu.Game/Beatmaps/BeatmapStore.cs
+++ b/osu.Game/Beatmaps/BeatmapStore.cs
@@ -64,7 +64,8 @@ namespace osu.Game.Beatmaps
base.AddIncludesForDeletion(query)
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
- .Include(s => s.Metadata);
+ .Include(s => s.Metadata)
+ .Include(s => s.Beatmaps).ThenInclude(b => b.Scores);
protected override IQueryable AddIncludesForConsumption(IQueryable query) =>
base.AddIncludesForConsumption(query)
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 8975ab8a0e..8df286ffb2 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -3,6 +3,7 @@
using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
+using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Game.Overlays;
using osu.Game.Rulesets.Scoring;
@@ -96,15 +97,25 @@ namespace osu.Game.Configuration
Set(OsuSetting.ScreenshotCaptureMenuCursor, false);
Set(OsuSetting.SongSelectRightMouseScroll, false);
+
+ Set(OsuSetting.Scaling, ScalingMode.Off);
+
+ Set(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f);
+ Set(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f);
+
+ Set(OsuSetting.ScalingPositionX, 0.5f, 0f, 1f);
+ Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
}
- public OsuConfigManager(Storage storage) : base(storage)
+ public OsuConfigManager(Storage storage)
+ : base(storage)
{
}
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
{
- new TrackedSetting(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled"))
+ new TrackedSetting(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled")),
+ new TrackedSetting(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())),
};
}
@@ -151,6 +162,11 @@ namespace osu.Game.Configuration
BeatmapHitsounds,
IncreaseFirstObjectVisibility,
ScoreDisplayMode,
- ExternalLinkWarning
+ ExternalLinkWarning,
+ Scaling,
+ ScalingPositionX,
+ ScalingPositionY,
+ ScalingSizeX,
+ ScalingSizeY
}
}
diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs
new file mode 100644
index 0000000000..b907d55d82
--- /dev/null
+++ b/osu.Game/Configuration/ScalingMode.cs
@@ -0,0 +1,16 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.ComponentModel;
+
+namespace osu.Game.Configuration
+{
+ public enum ScalingMode
+ {
+ Off,
+ Everything,
+ [Description("Excluding overlays")]
+ ExcludeOverlays,
+ Gameplay,
+ }
+}
diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs
new file mode 100644
index 0000000000..ff7a1cdacf
--- /dev/null
+++ b/osu.Game/Graphics/Containers/ScalingContainer.cs
@@ -0,0 +1,120 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Configuration;
+using osu.Game.Graphics.Backgrounds;
+using osuTK;
+
+namespace osu.Game.Graphics.Containers
+{
+ ///
+ /// Handles user-defined scaling, allowing application at multiple levels defined by .
+ ///
+ public class ScalingContainer : Container
+ {
+ private Bindable sizeX;
+ private Bindable sizeY;
+ private Bindable posX;
+ private Bindable posY;
+
+ private readonly ScalingMode? targetMode;
+
+ private Bindable scalingMode;
+
+ private readonly Container content;
+ protected override Container Content => content;
+
+ private readonly Container sizableContainer;
+
+ private Drawable backgroundLayer;
+
+ ///
+ /// Create a new instance.
+ ///
+ /// The mode which this container should be handling. Handles all modes if null.
+ public ScalingContainer(ScalingMode? targetMode = null)
+ {
+ this.targetMode = targetMode;
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChild = sizableContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ RelativePositionAxes = Axes.Both,
+ CornerRadius = 10,
+ Child = content = new DrawSizePreservingFillContainer()
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager config)
+ {
+ scalingMode = config.GetBindable(OsuSetting.Scaling);
+ scalingMode.ValueChanged += _ => updateSize();
+
+ sizeX = config.GetBindable(OsuSetting.ScalingSizeX);
+ sizeX.ValueChanged += _ => updateSize();
+
+ sizeY = config.GetBindable(OsuSetting.ScalingSizeY);
+ sizeY.ValueChanged += _ => updateSize();
+
+ posX = config.GetBindable(OsuSetting.ScalingPositionX);
+ posX.ValueChanged += _ => updateSize();
+
+ posY = config.GetBindable(OsuSetting.ScalingPositionY);
+ posY.ValueChanged += _ => updateSize();
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ updateSize();
+ sizableContainer.FinishTransforms();
+ }
+
+ private bool requiresBackgroundVisible => (scalingMode == ScalingMode.Everything || scalingMode == ScalingMode.ExcludeOverlays) && (sizeX.Value != 1 || sizeY.Value != 1);
+
+ private void updateSize()
+ {
+ if (targetMode == ScalingMode.Everything)
+ {
+ // the top level scaling container manages the background to be displayed while scaling.
+ if (requiresBackgroundVisible)
+ {
+ if (backgroundLayer == null)
+ LoadComponentAsync(backgroundLayer = new Background("Menu/menu-background-1")
+ {
+ Colour = OsuColour.Gray(0.1f),
+ Alpha = 0,
+ Depth = float.MaxValue
+ }, d =>
+ {
+ AddInternal(d);
+ d.FadeTo(requiresBackgroundVisible ? 1 : 0, 4000, Easing.OutQuint);
+ });
+ else
+ backgroundLayer.FadeIn(500);
+ }
+ else
+ backgroundLayer?.FadeOut(500);
+ }
+
+ bool scaling = targetMode == null || scalingMode.Value == targetMode;
+
+ var targetSize = scaling ? new Vector2(sizeX, sizeY) : Vector2.One;
+ var targetPosition = scaling ? new Vector2(posX, posY) * (Vector2.One - targetSize) : Vector2.Zero;
+ bool requiresMasking = scaling && targetSize != Vector2.One;
+
+ if (requiresMasking)
+ sizableContainer.Masking = true;
+
+ sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart);
+ sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index a59abcbcee..2bd84ab2b4 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -8,7 +8,6 @@ using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
-using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Graphics.Cursor;
@@ -33,38 +32,7 @@ namespace osu.Game.Graphics.UserInterface
private readonly Box leftBox;
private readonly Box rightBox;
- public virtual string TooltipText
- {
- get
- {
- var bindableDouble = CurrentNumber as BindableNumber;
- var bindableFloat = CurrentNumber as BindableNumber;
- var floatValue = bindableDouble?.Value ?? bindableFloat?.Value;
- var floatPrecision = bindableDouble?.Precision ?? bindableFloat?.Precision;
-
- if (floatValue != null)
- {
- var floatMinValue = bindableDouble?.MinValue ?? bindableFloat.MinValue;
- var floatMaxValue = bindableDouble?.MaxValue ?? bindableFloat.MaxValue;
-
- if (floatMaxValue == 1 && (floatMinValue == 0 || floatMinValue == -1))
- return floatValue.Value.ToString("P0");
-
- var decimalPrecision = normalise((decimal)floatPrecision, max_decimal_digits);
-
- // Find the number of significant digits (we could have less than 5 after normalize())
- var significantDigits = findPrecision(decimalPrecision);
-
- return floatValue.Value.ToString($"N{significantDigits}");
- }
-
- var bindableInt = CurrentNumber as BindableNumber;
- if (bindableInt != null)
- return bindableInt.Value.ToString("N0");
-
- return Current.Value.ToString(CultureInfo.InvariantCulture);
- }
- }
+ public virtual string TooltipText { get; private set; }
private Color4 accentColour;
public Color4 AccentColour
@@ -136,21 +104,34 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(e);
}
- protected override void OnUserChange()
+ protected override bool OnMouseDown(MouseDownEvent e)
{
- base.OnUserChange();
- playSample();
+ Nub.Current.Value = true;
+ return base.OnMouseDown(e);
}
- private void playSample()
+ protected override bool OnMouseUp(MouseUpEvent e)
+ {
+ Nub.Current.Value = false;
+ return base.OnMouseUp(e);
+ }
+
+ protected override void OnUserChange(T value)
+ {
+ base.OnUserChange(value);
+ playSample(value);
+ updateTooltipText(value);
+ }
+
+ private void playSample(T value)
{
if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
return;
- if (Current.Value.Equals(lastSampleValue))
+ if (value.Equals(lastSampleValue))
return;
- lastSampleValue = Current.Value;
+ lastSampleValue = value;
lastSampleTime = Clock.CurrentTime;
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
@@ -163,16 +144,28 @@ namespace osu.Game.Graphics.UserInterface
sample.Play();
}
- protected override bool OnMouseDown(MouseDownEvent e)
+ private void updateTooltipText(T value)
{
- Nub.Current.Value = true;
- return base.OnMouseDown(e);
- }
+ if (CurrentNumber.IsInteger)
+ TooltipText = ((int)Convert.ChangeType(value, typeof(int))).ToString("N0");
+ else
+ {
+ double floatValue = (double)Convert.ChangeType(value, typeof(double));
+ double floatMinValue = (double)Convert.ChangeType(CurrentNumber.MinValue, typeof(double));
+ double floatMaxValue = (double)Convert.ChangeType(CurrentNumber.MaxValue, typeof(double));
- protected override bool OnMouseUp(MouseUpEvent e)
- {
- Nub.Current.Value = false;
- return base.OnMouseUp(e);
+ if (floatMaxValue == 1 && floatMinValue >= -1)
+ TooltipText = floatValue.ToString("P0");
+ else
+ {
+ var decimalPrecision = normalise((decimal)Convert.ChangeType(CurrentNumber.Precision, typeof(decimal)), max_decimal_digits);
+
+ // Find the number of significant digits (we could have less than 5 after normalize())
+ var significantDigits = findPrecision(decimalPrecision);
+
+ TooltipText = floatValue.ToString($"N{significantDigits}");
+ }
+ }
}
protected override void UpdateAfterChildren()
diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs
index ee64c7c25c..6dca58f70d 100644
--- a/osu.Game/Graphics/UserInterface/ProgressBar.cs
+++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs
@@ -62,6 +62,6 @@ namespace osu.Game.Graphics.UserInterface
fill.Width = value * UsableWidth;
}
- protected override void OnUserChange() => OnSeek?.Invoke(Current);
+ protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
}
}
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index 8026847e3b..2dafedc3ac 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Migrations
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.1.4-rtm-31024");
+ .HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
@@ -215,6 +215,25 @@ namespace osu.Game.Migrations
b.ToTable("Settings");
});
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
{
b.Property("ID")
@@ -239,25 +258,6 @@ namespace osu.Game.Migrations
b.ToTable("KeyBinding");
});
- modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd();
-
- b.Property("Hash");
-
- b.Property("ReferenceCount");
-
- b.HasKey("ID");
-
- b.HasIndex("Hash")
- .IsUnique();
-
- b.HasIndex("ReferenceCount");
-
- b.ToTable("FileInfo");
- });
-
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
{
b.Property("ID")
@@ -454,7 +454,7 @@ namespace osu.Game.Migrations
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
- .WithMany()
+ .WithMany("Scores")
.HasForeignKey("BeatmapInfoID")
.OnDelete(DeleteBehavior.Cascade);
diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs
index 10b4e73419..db273dd00a 100644
--- a/osu.Game/Online/API/APIAccess.cs
+++ b/osu.Game/Online/API/APIAccess.cs
@@ -101,6 +101,9 @@ namespace osu.Game.Online.API
//todo: replace this with a ping request.
log.Add(@"In a failing state, waiting a bit before we try again...");
Thread.Sleep(5000);
+
+ if (!IsLoggedIn) goto case APIState.Connecting;
+
if (queue.Count == 0)
{
log.Add(@"Queueing a ping request");
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 702b1ae108..bb356ce7f0 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -26,6 +26,7 @@ using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Input;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
@@ -187,6 +188,7 @@ namespace osu.Game
}
private ExternalLinkOpener externalLinkOpener;
+
public void OpenUrlExternally(string url)
{
if (url.StartsWith("/"))
@@ -353,7 +355,11 @@ namespace osu.Game
ActionRequested = action => volume.Adjust(action),
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
},
- mainContent = new Container { RelativeSizeAxes = Axes.Both },
+ screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ mainContent = new DrawSizePreservingFillContainer(),
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
idleTracker = new IdleTracker(6000)
});
@@ -362,7 +368,7 @@ namespace osu.Game
{
screenStack.ModePushed += screenAdded;
screenStack.Exited += screenRemoved;
- mainContent.Add(screenStack);
+ screenContainer.Add(screenStack);
});
loadComponentSingleFile(Toolbar = new Toolbar
@@ -497,7 +503,7 @@ namespace osu.Game
if (notifications.State == Visibility.Visible)
offset -= ToolbarButton.WIDTH / 2;
- screenStack.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
+ screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
}
settings.StateChanged += _ => updateScreenOffset();
@@ -555,7 +561,7 @@ namespace osu.Game
focused.StateChanged += s =>
{
visibleOverlayCount += s == Visibility.Visible ? 1 : -1;
- screenStack.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
+ screenContainer.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
};
}
@@ -646,6 +652,7 @@ namespace osu.Game
private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig;
+ private ScalingContainer screenContainer;
protected override bool OnExiting()
{
@@ -685,7 +692,7 @@ namespace osu.Game
ruleset.Disabled = applyBeatmapRulesetRestrictions;
Beatmap.Disabled = applyBeatmapRulesetRestrictions;
- mainContent.Padding = new MarginPadding { Top = ToolbarOffset };
+ screenContainer.Padding = new MarginPadding { Top = ToolbarOffset };
MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
}
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 683fa30818..b6c642c9dc 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -24,6 +24,7 @@ using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Audio;
using osu.Game.Database;
+using osu.Game.Graphics.Containers;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.IO;
@@ -189,7 +190,7 @@ namespace osu.Game
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
- base.Content.Add(new DrawSizePreservingFillContainer { Child = MenuCursorContainer });
+ base.Content.Add(new ScalingContainer(ScalingMode.Everything) { Child = MenuCursorContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
@@ -247,7 +248,8 @@ namespace osu.Game
var extension = Path.GetExtension(paths.First())?.ToLowerInvariant();
foreach (var importer in fileImporters)
- if (importer.HandledExtensions.Contains(extension)) importer.Import(paths);
+ if (importer.HandledExtensions.Contains(extension))
+ importer.Import(paths);
}
public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray();
diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
index 94ee9d4bf6..c02215d690 100644
--- a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
+++ b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using System.Collections.Generic;
using System.Linq;
using osuTK;
@@ -18,7 +19,7 @@ namespace osu.Game.Overlays.Chat.Selection
public readonly FillFlowContainer ChannelFlow;
public IEnumerable FilterableChildren => ChannelFlow.Children;
- public IEnumerable FilterTerms => new[] { Header };
+ public IEnumerable FilterTerms => Array.Empty();
public bool MatchingFilter
{
set
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
index ca9a527fad..3fa4276616 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
@@ -6,9 +6,14 @@ using System.Drawing;
using System.Linq;
using osu.Framework.Allocation;
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.Game.Configuration;
+using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
+using osuTK.Graphics;
namespace osu.Game.Overlays.Settings.Sections.Graphics
{
@@ -16,20 +21,33 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{
protected override string Header => "Layout";
+ private FillFlowContainer> scalingSettings;
+
+ private Bindable scalingMode;
private Bindable sizeFullscreen;
private OsuGameBase game;
private SettingsDropdown resolutionDropdown;
private SettingsEnumDropdown windowModeDropdown;
+ private Bindable scalingPositionX;
+ private Bindable scalingPositionY;
+ private Bindable scalingSizeX;
+ private Bindable scalingSizeY;
+
private const int transition_duration = 400;
[BackgroundDependencyLoader]
- private void load(FrameworkConfigManager config, OsuGameBase game)
+ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game)
{
this.game = game;
+ scalingMode = osuConfig.GetBindable(OsuSetting.Scaling);
sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen);
+ scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX);
+ scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY);
+ scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX);
+ scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY);
Container resolutionSettingsContainer;
@@ -45,8 +63,51 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
+ new SettingsEnumDropdown
+ {
+ LabelText = "Scaling",
+ Bindable = osuConfig.GetBindable(OsuSetting.Scaling),
+ },
+ scalingSettings = new FillFlowContainer>
+ {
+ Direction = FillDirection.Vertical,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ AutoSizeDuration = transition_duration,
+ AutoSizeEasing = Easing.OutQuint,
+ Masking = true,
+ Children = new []
+ {
+ new SettingsSlider
+ {
+ LabelText = "Horizontal position",
+ Bindable = scalingPositionX,
+ KeyboardStep = 0.01f
+ },
+ new SettingsSlider
+ {
+ LabelText = "Vertical position",
+ Bindable = scalingPositionY,
+ KeyboardStep = 0.01f
+ },
+ new SettingsSlider
+ {
+ LabelText = "Horizontal scale",
+ Bindable = scalingSizeX,
+ KeyboardStep = 0.01f
+ },
+ new SettingsSlider
+ {
+ LabelText = "Vertical scale",
+ Bindable = scalingSizeY,
+ KeyboardStep = 0.01f
+ },
+ }
+ },
};
+ scalingSettings.ForEach(s => bindPreviewEvent(s.Bindable));
+
var resolutions = getResolutions();
if (resolutions.Count > 1)
@@ -70,6 +131,45 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
resolutionDropdown.Hide();
}, true);
}
+
+ scalingMode.BindValueChanged(mode =>
+ {
+ scalingSettings.ClearTransforms();
+ scalingSettings.AutoSizeAxes = mode != ScalingMode.Off ? Axes.Y : Axes.None;
+
+ if (mode == ScalingMode.Off)
+ scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
+
+ scalingSettings.ForEach(s => s.TransferValueOnCommit = mode == ScalingMode.Everything);
+ }, true);
+ }
+
+ ///
+ /// Create a delayed bindable which only updates when a condition is met.
+ ///
+ /// The config bindable.
+ /// A bindable which will propagate updates with a delay.
+ private void bindPreviewEvent(Bindable bindable)
+ {
+ bindable.ValueChanged += v =>
+ {
+ 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();
}
private IReadOnlyList getResolutions()
@@ -89,6 +189,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
return resolutions;
}
+ private class ScalingPreview : ScalingContainer
+ {
+ public ScalingPreview()
+ {
+ Child = new Box
+ {
+ Colour = Color4.White,
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0.5f,
+ };
+ }
+ }
+
private class ResolutionSettingsDropdown : SettingsDropdown
{
protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl { Items = Items };
diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs
index a3698c36e6..39a974dd2e 100644
--- a/osu.Game/Overlays/Settings/SettingsSlider.cs
+++ b/osu.Game/Overlays/Settings/SettingsSlider.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
@@ -23,14 +22,16 @@ namespace osu.Game.Overlays.Settings
RelativeSizeAxes = Axes.X
};
- public float KeyboardStep;
-
- [BackgroundDependencyLoader]
- private void load()
+ public bool TransferValueOnCommit
{
- var slider = Control as U;
- if (slider != null)
- slider.KeyboardStep = KeyboardStep;
+ get => ((U)Control).TransferValueOnCommit;
+ set => ((U)Control).TransferValueOnCommit = value;
+ }
+
+ public float KeyboardStep
+ {
+ get => ((U)Control).KeyboardStep;
+ set => ((U)Control).KeyboardStep = value;
}
}
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
new file mode 100644
index 0000000000..c097d25178
--- /dev/null
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
@@ -0,0 +1,27 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Screens;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Backgrounds
+{
+ public class BackgroundScreenBlack : BackgroundScreen
+ {
+ public BackgroundScreenBlack()
+ {
+ Child = new Box
+ {
+ Colour = Color4.Black,
+ RelativeSizeAxes = Axes.Both,
+ };
+ }
+
+ protected override void OnEntering(Screen last)
+ {
+ Show();
+ }
+ }
+}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs
deleted file mode 100644
index 5e08db8907..0000000000
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Screens.Backgrounds
-{
- public class BackgroundScreenEmpty : BackgroundScreen
- {
- }
-}
diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
index aa63b02013..373f4d1682 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
@@ -238,11 +238,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
case Key.Right:
beatDivisor.Next();
- OnUserChange();
+ OnUserChange(Current);
return true;
case Key.Left:
beatDivisor.Previous();
- OnUserChange();
+ OnUserChange(Current);
return true;
default:
return false;
@@ -279,7 +279,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
var xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
CurrentNumber.Value = availableDivisors.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
- OnUserChange();
+ OnUserChange(Current);
}
private float getMappedPosition(float divisor) => (float)Math.Pow((divisor - 1) / (availableDivisors.Last() - 1), 0.90f);
diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs
index fa01411a0f..8d9cd8dbe9 100644
--- a/osu.Game/Screens/Menu/Intro.cs
+++ b/osu.Game/Screens/Menu/Intro.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Menu
public override bool CursorVisible => false;
- protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
+ protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
private Bindable menuVoice;
private Bindable menuMusic;
diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs
index ec5528b13f..188e95ced5 100644
--- a/osu.Game/Screens/Menu/MenuSideFlashes.cs
+++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs
@@ -58,6 +58,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
+ Height = 1.5f,
// align off-screen to make sure our edges don't become visible during parallax.
X = -box_width,
Alpha = 0,
@@ -70,6 +71,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
+ Height = 1.5f,
X = box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 14dc644100..d5c99f5729 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -20,6 +20,7 @@ using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Online.API;
using osu.Game.Overlays;
@@ -179,10 +180,13 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
- new LocalSkinOverrideContainer(working.Skin)
+ new ScalingContainer(ScalingMode.Gameplay)
{
- RelativeSizeAxes = Axes.Both,
- Child = RulesetContainer
+ Child = new LocalSkinOverrideContainer(working.Skin)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = RulesetContainer
+ }
},
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
{
@@ -191,7 +195,10 @@ namespace osu.Game.Screens.Play
ProcessCustomClock = false,
Breaks = beatmap.Breaks
},
- RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
+ new ScalingContainer(ScalingMode.Gameplay)
+ {
+ Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
+ },
hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
{
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
diff --git a/osu.Game/Screens/Play/SongProgressBar.cs b/osu.Game/Screens/Play/SongProgressBar.cs
index 1f0c4936a5..b06a34e603 100644
--- a/osu.Game/Screens/Play/SongProgressBar.cs
+++ b/osu.Game/Screens/Play/SongProgressBar.cs
@@ -112,6 +112,6 @@ namespace osu.Game.Screens.Play
handleBase.X = xFill;
}
- protected override void OnUserChange() => OnSeek?.Invoke(Current);
+ protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index d6dbb6f11c..8f00e81237 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -18,7 +18,7 @@
-
+