diff --git a/osu-resources b/osu-resources index 7bb0782200..6e145ed502 160000 --- a/osu-resources +++ b/osu-resources @@ -1 +1 @@ -Subproject commit 7bb0782200abadf73b79ed1a3bc1d5b926c6a81e +Subproject commit 6e145ed50274539ee827fdc3d1fda1e130b070fd diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 3d927ef67c..70260b349e 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -82,6 +82,8 @@ namespace osu.Game.Configuration Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer); Set(OsuSetting.Version, string.Empty); + + Set(OsuSetting.ScreenshotFormat, ScreenshotFormat.Jpg); } public OsuConfigManager(Storage storage) : base(storage) @@ -125,6 +127,7 @@ namespace osu.Game.Configuration Version, ShowConvertedBeatmaps, SpeedChangeVisualisation, - Skin + Skin, + ScreenshotFormat } } diff --git a/osu.Game/Configuration/ScreenshotFormat.cs b/osu.Game/Configuration/ScreenshotFormat.cs index 1bc3013af9..b9309fae3a 100644 --- a/osu.Game/Configuration/ScreenshotFormat.cs +++ b/osu.Game/Configuration/ScreenshotFormat.cs @@ -7,7 +7,6 @@ namespace osu.Game.Configuration { public enum ScreenshotFormat { - Bmp = 0, // TODO: Figure out the best way to hide this from the dropdown [Description("JPG (web-friendly)")] Jpg = 1, [Description("PNG (lossless)")] diff --git a/osu.Game/Graphics/ScreenshotManager.cs b/osu.Game/Graphics/ScreenshotManager.cs new file mode 100644 index 0000000000..b0cd997837 --- /dev/null +++ b/osu.Game/Graphics/ScreenshotManager.cs @@ -0,0 +1,110 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Drawing.Imaging; +using System.IO; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Configuration; +using osu.Framework.Graphics.Containers; +using osu.Framework.Input; +using osu.Framework.Input.Bindings; +using osu.Framework.Platform; +using osu.Game.Configuration; +using osu.Game.Input.Bindings; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; + +namespace osu.Game.Graphics +{ + public class ScreenshotManager : Container, IKeyBindingHandler, IHandleGlobalInput + { + private Bindable screenshotFormat; + private GameHost host; + private Storage storage; + private NotificationOverlay notificationOverlay; + + private SampleChannel shutter; + + [BackgroundDependencyLoader] + private void load(GameHost host, OsuConfigManager config, Storage storage, NotificationOverlay notificationOverlay, AudioManager audio) + { + this.host = host; + this.storage = storage.GetStorageForDirectory(@"screenshots"); + this.notificationOverlay = notificationOverlay; + + screenshotFormat = config.GetBindable(OsuSetting.ScreenshotFormat); + + shutter = audio.Sample.Get("UI/shutter"); + } + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.TakeScreenshot: + shutter.Play(); + TakeScreenshotAsync(); + return true; + } + + return false; + } + + public bool OnReleased(GlobalAction action) => false; + + public async void TakeScreenshotAsync() + { + using (var bitmap = await host.TakeScreenshotAsync()) + { + var fileName = getFileName(); + if (fileName == null) return; + + var stream = storage.GetStream(fileName, FileAccess.Write); + + switch (screenshotFormat.Value) + { + case ScreenshotFormat.Png: + bitmap.Save(stream, ImageFormat.Png); + break; + case ScreenshotFormat.Jpg: + bitmap.Save(stream, ImageFormat.Jpeg); + break; + default: + throw new ArgumentOutOfRangeException(nameof(screenshotFormat)); + } + + notificationOverlay.Post(new SimpleNotification + { + Text = $"{fileName} saved!", + Activated = () => + { + storage.OpenInNativeExplorer(); + return true; + } + }); + } + } + + private string getFileName() + { + var dt = DateTime.Now; + var fileExt = screenshotFormat.ToString().ToLower(); + + var withoutIndex = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}.{fileExt}"; + if (!storage.Exists(withoutIndex)) + return withoutIndex; + + for (ulong i = 1; i < ulong.MaxValue; i++) + { + var indexedName = $"osu_{dt:yyyy-MM-dd_HH-mm-ss}-{i}.{fileExt}"; + if (!storage.Exists(indexedName)) + return indexedName; + } + + return null; + } + } +} diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 17ec2af4b9..97e473a797 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -26,6 +26,8 @@ namespace osu.Game.Input.Bindings { new KeyBinding(InputKey.F8, GlobalAction.ToggleChat), new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial), + new KeyBinding(InputKey.F12,GlobalAction.TakeScreenshot), + new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings), new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar), new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings), @@ -72,5 +74,8 @@ namespace osu.Game.Input.Bindings SkipCutscene, [Description("Quick Retry (Hold)")] QuickRetry, + + [Description("Take screenshot")] + TakeScreenshot } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4a40a6b5df..89447b8ed6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -133,7 +133,6 @@ namespace osu.Game // bind config int to database SkinInfo configSkin = LocalConfig.GetBindable(OsuSetting.Skin); - SkinManager.CurrentSkinInfo.ValueChanged += s => configSkin.Value = s.ID; configSkin.ValueChanged += id => SkinManager.CurrentSkinInfo.Value = SkinManager.Query(s => s.ID == id) ?? SkinInfo.Default; configSkin.TriggerChange(); @@ -240,6 +239,7 @@ namespace osu.Game loadComponentSingleFile(volume = new VolumeOverlay(), overlayContent.Add); loadComponentSingleFile(onscreenDisplay = new OnScreenDisplay(), Add); + loadComponentSingleFile(new ScreenshotManager(), Add); //overlay elements loadComponentSingleFile(direct = new DirectOverlay { Depth = -1 }, mainContent.Add); diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs index b9d76c05f0..fa57a85454 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs @@ -1,6 +1,8 @@ // 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.Graphics; using osu.Game.Configuration; namespace osu.Game.Overlays.Settings.Sections.Graphics @@ -12,7 +14,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics [BackgroundDependencyLoader] private void load(OsuConfigManager config) { - Children = new[] + Children = new Drawable[] { new SettingsCheckbox { @@ -24,6 +26,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics LabelText = "Rotate cursor when dragging", Bindable = config.GetBindable(OsuSetting.CursorRotation) }, + new SettingsEnumDropdown + { + LabelText = "Screenshot format", + Bindable = config.GetBindable(OsuSetting.ScreenshotFormat) + } }; } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 72bc70de51..ab058d90d9 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -187,6 +187,7 @@ $(SolutionDir)\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + $(SolutionDir)\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll @@ -290,6 +291,7 @@ +