1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 14:57:52 +08:00

Merge branch 'master' into fix-first-hitobject-must-be-combo

This commit is contained in:
Dan Balasescu 2020-10-07 16:21:00 +09:00 committed by GitHub
commit fbb10f6774
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 492 additions and 321 deletions

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Origin = Anchor.Centre; Origin = Anchor.Centre;
Masking = true; Masking = true;
BorderThickness = 10; BorderThickness = 9; // roughly matches slider borders and makes stacked circles distinctly visible from each other.
BorderColour = Color4.White; BorderColour = Color4.White;
Child = new Box Child = new Box

View File

@ -49,6 +49,23 @@ namespace osu.Game.Rulesets.Osu.Skinning
{ {
OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject; OsuHitObject osuObject = (OsuHitObject)drawableObject.HitObject;
bool allowFallback = false;
// attempt lookup using priority specification
Texture baseTexture = getTextureWithFallback(string.Empty);
// if the base texture was not found without a fallback, switch on fallback mode and re-perform the lookup.
if (baseTexture == null)
{
allowFallback = true;
baseTexture = getTextureWithFallback(string.Empty);
}
// at this point, any further texture fetches should be correctly using the priority source if the base texture was retrieved using it.
// the flow above handles the case where a sliderendcircle.png is retrieved from the skin, but sliderendcircleoverlay.png doesn't exist.
// expected behaviour in this scenario is not showing the overlay, rather than using hitcircleoverlay.png (potentially from the default/fall-through skin).
Texture overlayTexture = getTextureWithFallback("overlay");
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
circleSprites = new Container<Sprite> circleSprites = new Container<Sprite>
@ -60,13 +77,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
{ {
hitCircleSprite = new Sprite hitCircleSprite = new Sprite
{ {
Texture = getTextureWithFallback(string.Empty), Texture = baseTexture,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
}, },
hitCircleOverlay = new Sprite hitCircleOverlay = new Sprite
{ {
Texture = getTextureWithFallback("overlay"), Texture = overlayTexture,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
} }
@ -101,8 +118,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
Texture tex = null; Texture tex = null;
if (!string.IsNullOrEmpty(priorityLookup)) if (!string.IsNullOrEmpty(priorityLookup))
{
tex = skin.GetTexture($"{priorityLookup}{name}"); tex = skin.GetTexture($"{priorityLookup}{name}");
if (!allowFallback)
return tex;
}
return tex ?? skin.GetTexture($"hitcircle{name}"); return tex ?? skin.GetTexture($"hitcircle{name}");
} }
} }

View File

@ -69,7 +69,7 @@ namespace osu.Game.Tests.Visual.Editing
using (var zip = ZipArchive.Open(temp)) using (var zip = ZipArchive.Open(temp))
zip.WriteToDirectory(extractedFolder); zip.WriteToDirectory(extractedFolder);
bool success = setup.ChangeAudioTrack(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3")); bool success = setup.ChildrenOfType<ResourcesSection>().First().ChangeAudioTrack(Path.Combine(extractedFolder, "03. Renatus - Soleily 192kbps.mp3"));
File.Delete(temp); File.Delete(temp);
Directory.Delete(extractedFolder, true); Directory.Delete(extractedFolder, true);

View File

@ -54,6 +54,13 @@ namespace osu.Game.Overlays.Settings
} }
} }
[Obsolete("Use Current instead")] // Can be removed 20210406
public Bindable<T> Bindable
{
get => Current;
set => Current = value;
}
public virtual Bindable<T> Current public virtual Bindable<T> Current
{ {
get => controlWithCurrent.Current; get => controlWithCurrent.Current;

View File

@ -77,6 +77,7 @@ namespace osu.Game.Rulesets.Objects
/// <summary> /// <summary>
/// The hit windows for this <see cref="HitObject"/>. /// The hit windows for this <see cref="HitObject"/>.
/// </summary> /// </summary>
[JsonIgnore]
public HitWindows HitWindows { get; set; } public HitWindows HitWindows { get; set; }
private readonly List<HitObject> nestedHitObjects = new List<HitObject>(); private readonly List<HitObject> nestedHitObjects = new List<HitObject>();

View File

@ -199,7 +199,40 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
base.Update(); base.Update();
// no bindable so we perform this every update // no bindable so we perform this every update
Width = (float)(HitObject.GetEndTime() - HitObject.StartTime); float duration = (float)(HitObject.GetEndTime() - HitObject.StartTime);
if (Width != duration)
{
Width = duration;
// kind of haphazard but yeah, no bindables.
if (HitObject is IHasRepeats repeats)
updateRepeats(repeats);
}
}
private Container repeatsContainer;
private void updateRepeats(IHasRepeats repeats)
{
repeatsContainer?.Expire();
mainComponents.Add(repeatsContainer = new Container
{
RelativeSizeAxes = Axes.Both,
});
for (int i = 0; i < repeats.RepeatCount; i++)
{
repeatsContainer.Add(new Circle
{
Size = new Vector2(circle_size / 2),
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
X = (float)(i + 1) / (repeats.RepeatCount + 1),
});
}
} }
protected override bool ShouldBeConsideredForInput(Drawable child) => true; protected override bool ShouldBeConsideredForInput(Drawable child) => true;

View File

@ -234,25 +234,19 @@ namespace osu.Game.Screens.Edit
applyFunction(this); applyFunction(this);
beatmapProcessor?.PreProcess(); beatmapProcessor?.PreProcess();
foreach (var h in batchPendingDeletes) processHitObject(h);
foreach (var h in batchPendingInserts) processHitObject(h);
beatmapProcessor?.PostProcess(); beatmapProcessor?.PostProcess();
isBatchApplying = false; foreach (var h in batchPendingDeletes) HitObjectRemoved?.Invoke(h);
foreach (var h in batchPendingInserts) HitObjectAdded?.Invoke(h);
foreach (var h in batchPendingDeletes)
{
processHitObject(h);
HitObjectRemoved?.Invoke(h);
}
batchPendingDeletes.Clear(); batchPendingDeletes.Clear();
foreach (var h in batchPendingInserts)
{
processHitObject(h);
HitObjectAdded?.Invoke(h);
}
batchPendingInserts.Clear(); batchPendingInserts.Clear();
isBatchApplying = false;
} }
/// <summary> /// <summary>

View File

@ -86,7 +86,7 @@ namespace osu.Game.Screens.Edit
/// </summary> /// </summary>
/// <param name="snapped">Whether to snap to the closest beat after seeking.</param> /// <param name="snapped">Whether to snap to the closest beat after seeking.</param>
/// <param name="amount">The relative amount (magnitude) which should be seeked.</param> /// <param name="amount">The relative amount (magnitude) which should be seeked.</param>
public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount); public void SeekBackward(bool snapped = false, double amount = 1) => seek(-1, snapped, amount + (IsRunning ? 1.5 : 0));
/// <summary> /// <summary>
/// Seeks forwards by one beat length. /// Seeks forwards by one beat length.

View File

@ -0,0 +1,73 @@
// 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.IO;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Screens.Edit.Setup
{
/// <summary>
/// A labelled textbox which reveals an inline file chooser when clicked.
/// </summary>
internal class FileChooserLabelledTextBox : LabelledTextBox
{
public Container Target;
private readonly IBindable<FileInfo> currentFile = new Bindable<FileInfo>();
public FileChooserLabelledTextBox()
{
currentFile.BindValueChanged(onFileSelected);
}
private void onFileSelected(ValueChangedEvent<FileInfo> file)
{
if (file.NewValue == null)
return;
Target.Clear();
Current.Value = file.NewValue.FullName;
}
protected override OsuTextBox CreateTextBox() =>
new FileChooserOsuTextBox
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
CornerRadius = CORNER_RADIUS,
OnFocused = DisplayFileChooser
};
public void DisplayFileChooser()
{
Target.Child = new FileSelector(validFileExtensions: ResourcesSection.AudioExtensions)
{
RelativeSizeAxes = Axes.X,
Height = 400,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
CurrentFile = { BindTarget = currentFile }
};
}
internal class FileChooserOsuTextBox : OsuTextBox
{
public Action OnFocused;
protected override void OnFocus(FocusEvent e)
{
OnFocused?.Invoke();
base.OnFocus(e);
GetContainingInputManager().TriggerFocusContention(this);
}
}
}
}

View File

@ -0,0 +1,71 @@
// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterfaceV2;
namespace osu.Game.Screens.Edit.Setup
{
internal class MetadataSection : SetupSection
{
private LabelledTextBox artistTextBox;
private LabelledTextBox titleTextBox;
private LabelledTextBox creatorTextBox;
private LabelledTextBox difficultyTextBox;
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
new OsuSpriteText
{
Text = "Beatmap metadata"
},
artistTextBox = new LabelledTextBox
{
Label = "Artist",
Current = { Value = Beatmap.Value.Metadata.Artist },
TabbableContentContainer = this
},
titleTextBox = new LabelledTextBox
{
Label = "Title",
Current = { Value = Beatmap.Value.Metadata.Title },
TabbableContentContainer = this
},
creatorTextBox = new LabelledTextBox
{
Label = "Creator",
Current = { Value = Beatmap.Value.Metadata.AuthorString },
TabbableContentContainer = this
},
difficultyTextBox = new LabelledTextBox
{
Label = "Difficulty Name",
Current = { Value = Beatmap.Value.BeatmapInfo.Version },
TabbableContentContainer = this
},
};
foreach (var item in Children.OfType<LabelledTextBox>())
item.OnCommit += onCommit;
}
private void onCommit(TextBox sender, bool newText)
{
if (!newText) return;
// for now, update these on commit rather than making BeatmapMetadata bindables.
// after switching database engines we can reconsider if switching to bindables is a good direction.
Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value;
Beatmap.Value.Metadata.Title = titleTextBox.Current.Value;
Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value;
Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value;
}
}
}

View File

@ -0,0 +1,211 @@
// 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.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays;
namespace osu.Game.Screens.Edit.Setup
{
internal class ResourcesSection : SetupSection, ICanAcceptFiles
{
private LabelledTextBox audioTrackTextBox;
private Container backgroundSpriteContainer;
public IEnumerable<string> HandledExtensions => ImageExtensions.Concat(AudioExtensions);
public static string[] ImageExtensions { get; } = { ".jpg", ".jpeg", ".png" };
public static string[] AudioExtensions { get; } = { ".mp3", ".ogg" };
[Resolved]
private OsuGameBase game { get; set; }
[Resolved]
private MusicController music { get; set; }
[Resolved]
private BeatmapManager beatmaps { get; set; }
[Resolved(canBeNull: true)]
private Editor editor { get; set; }
[BackgroundDependencyLoader]
private void load()
{
Container audioTrackFileChooserContainer = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
};
Children = new Drawable[]
{
backgroundSpriteContainer = new Container
{
RelativeSizeAxes = Axes.X,
Height = 250,
Masking = true,
CornerRadius = 10,
},
new OsuSpriteText
{
Text = "Resources"
},
audioTrackTextBox = new FileChooserLabelledTextBox
{
Label = "Audio Track",
Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" },
Target = audioTrackFileChooserContainer,
TabbableContentContainer = this
},
audioTrackFileChooserContainer,
};
updateBackgroundSprite();
audioTrackTextBox.Current.BindValueChanged(audioTrackChanged);
}
Task ICanAcceptFiles.Import(params string[] paths)
{
Schedule(() =>
{
var firstFile = new FileInfo(paths.First());
if (ImageExtensions.Contains(firstFile.Extension))
{
ChangeBackgroundImage(firstFile.FullName);
}
else if (AudioExtensions.Contains(firstFile.Extension))
{
audioTrackTextBox.Text = firstFile.FullName;
}
});
return Task.CompletedTask;
}
protected override void LoadComplete()
{
base.LoadComplete();
game.RegisterImportHandler(this);
}
public bool ChangeBackgroundImage(string path)
{
var info = new FileInfo(path);
if (!info.Exists)
return false;
var set = Beatmap.Value.BeatmapSetInfo;
// remove the previous background for now.
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile);
using (var stream = info.OpenRead())
{
if (oldFile != null)
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
else
beatmaps.AddFile(set, stream, info.Name);
}
Beatmap.Value.Metadata.BackgroundFile = info.Name;
updateBackgroundSprite();
return true;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
game?.UnregisterImportHandler(this);
}
public bool ChangeAudioTrack(string path)
{
var info = new FileInfo(path);
if (!info.Exists)
return false;
var set = Beatmap.Value.BeatmapSetInfo;
// remove the previous audio track for now.
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile);
using (var stream = info.OpenRead())
{
if (oldFile != null)
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
else
beatmaps.AddFile(set, stream, info.Name);
}
Beatmap.Value.Metadata.AudioFile = info.Name;
music.ReloadCurrentTrack();
editor?.UpdateClockSource();
return true;
}
private void audioTrackChanged(ValueChangedEvent<string> filePath)
{
if (!ChangeAudioTrack(filePath.NewValue))
audioTrackTextBox.Current.Value = filePath.OldValue;
}
private void updateBackgroundSprite()
{
LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value)
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fill,
}, background =>
{
if (background.Texture != null)
backgroundSpriteContainer.Child = background;
else
{
backgroundSpriteContainer.Children = new Drawable[]
{
new Box
{
Colour = Colours.GreySeafoamDarker,
RelativeSizeAxes = Axes.Both,
},
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 24))
{
Text = "Drag image here to set beatmap background!",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.X,
}
};
}
background.FadeInFromZero(500);
});
}
}
}

View File

@ -1,76 +1,33 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays; using osu.Game.Overlays;
using osuTK;
namespace osu.Game.Screens.Edit.Setup namespace osu.Game.Screens.Edit.Setup
{ {
public class SetupScreen : EditorScreen, ICanAcceptFiles public class SetupScreen : EditorScreen
{ {
public IEnumerable<string> HandledExtensions => ImageExtensions.Concat(AudioExtensions);
public static string[] ImageExtensions { get; } = { ".jpg", ".jpeg", ".png" };
public static string[] AudioExtensions { get; } = { ".mp3", ".ogg" };
private FillFlowContainer flow;
private LabelledTextBox artistTextBox;
private LabelledTextBox titleTextBox;
private LabelledTextBox creatorTextBox;
private LabelledTextBox difficultyTextBox;
private LabelledTextBox audioTrackTextBox;
private Container backgroundSpriteContainer;
[Resolved] [Resolved]
private OsuGameBase game { get; set; } private OsuColour colours { get; set; }
[Resolved] [Cached]
private MusicController music { get; set; } protected readonly OverlayColourProvider ColourProvider;
[Resolved]
private BeatmapManager beatmaps { get; set; }
[Resolved(canBeNull: true)]
private Editor editor { get; set; }
public SetupScreen() public SetupScreen()
: base(EditorScreenMode.SongSetup) : base(EditorScreenMode.SongSetup)
{ {
ColourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
} }
[Resolved]
private OsuColour colours { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Container audioTrackFileChooserContainer = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
};
Child = new Container Child = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -87,273 +44,33 @@ namespace osu.Game.Screens.Edit.Setup
Colour = colours.GreySeafoamDark, Colour = colours.GreySeafoamDark,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
new OsuScrollContainer new SectionsContainer<SetupSection>
{ {
FixedHeader = new SetupScreenHeader(),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(10), Children = new SetupSection[]
Child = flow = new FillFlowContainer
{ {
RelativeSizeAxes = Axes.X, new ResourcesSection(),
AutoSizeAxes = Axes.Y, new MetadataSection(),
Spacing = new Vector2(20), }
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
backgroundSpriteContainer = new Container
{
RelativeSizeAxes = Axes.X,
Height = 250,
Masking = true,
CornerRadius = 10,
},
new OsuSpriteText
{
Text = "Resources"
},
audioTrackTextBox = new FileChooserLabelledTextBox
{
Label = "Audio Track",
Current = { Value = Beatmap.Value.Metadata.AudioFile ?? "Click to select a track" },
Target = audioTrackFileChooserContainer,
TabbableContentContainer = this
},
audioTrackFileChooserContainer,
new OsuSpriteText
{
Text = "Beatmap metadata"
},
artistTextBox = new LabelledTextBox
{
Label = "Artist",
Current = { Value = Beatmap.Value.Metadata.Artist },
TabbableContentContainer = this
},
titleTextBox = new LabelledTextBox
{
Label = "Title",
Current = { Value = Beatmap.Value.Metadata.Title },
TabbableContentContainer = this
},
creatorTextBox = new LabelledTextBox
{
Label = "Creator",
Current = { Value = Beatmap.Value.Metadata.AuthorString },
TabbableContentContainer = this
},
difficultyTextBox = new LabelledTextBox
{
Label = "Difficulty Name",
Current = { Value = Beatmap.Value.BeatmapInfo.Version },
TabbableContentContainer = this
},
}
},
}, },
} }
} }
}; };
updateBackgroundSprite();
audioTrackTextBox.Current.BindValueChanged(audioTrackChanged);
foreach (var item in flow.OfType<LabelledTextBox>())
item.OnCommit += onCommit;
}
Task ICanAcceptFiles.Import(params string[] paths)
{
Schedule(() =>
{
var firstFile = new FileInfo(paths.First());
if (ImageExtensions.Contains(firstFile.Extension))
{
ChangeBackgroundImage(firstFile.FullName);
}
else if (AudioExtensions.Contains(firstFile.Extension))
{
audioTrackTextBox.Text = firstFile.FullName;
}
});
return Task.CompletedTask;
}
private void updateBackgroundSprite()
{
LoadComponentAsync(new BeatmapBackgroundSprite(Beatmap.Value)
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fill,
}, background =>
{
if (background.Texture != null)
backgroundSpriteContainer.Child = background;
else
{
backgroundSpriteContainer.Children = new Drawable[]
{
new Box
{
Colour = colours.GreySeafoamDarker,
RelativeSizeAxes = Axes.Both,
},
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 24))
{
Text = "Drag image here to set beatmap background!",
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.X,
}
};
}
background.FadeInFromZero(500);
});
}
protected override void LoadComplete()
{
base.LoadComplete();
game.RegisterImportHandler(this);
}
public bool ChangeBackgroundImage(string path)
{
var info = new FileInfo(path);
if (!info.Exists)
return false;
var set = Beatmap.Value.BeatmapSetInfo;
// remove the previous background for now.
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.BackgroundFile);
using (var stream = info.OpenRead())
{
if (oldFile != null)
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
else
beatmaps.AddFile(set, stream, info.Name);
}
Beatmap.Value.Metadata.BackgroundFile = info.Name;
updateBackgroundSprite();
return true;
}
public bool ChangeAudioTrack(string path)
{
var info = new FileInfo(path);
if (!info.Exists)
return false;
var set = Beatmap.Value.BeatmapSetInfo;
// remove the previous audio track for now.
// in the future we probably want to check if this is being used elsewhere (other difficulties?)
var oldFile = set.Files.FirstOrDefault(f => f.Filename == Beatmap.Value.Metadata.AudioFile);
using (var stream = info.OpenRead())
{
if (oldFile != null)
beatmaps.ReplaceFile(set, oldFile, stream, info.Name);
else
beatmaps.AddFile(set, stream, info.Name);
}
Beatmap.Value.Metadata.AudioFile = info.Name;
music.ReloadCurrentTrack();
editor?.UpdateClockSource();
return true;
}
private void audioTrackChanged(ValueChangedEvent<string> filePath)
{
if (!ChangeAudioTrack(filePath.NewValue))
audioTrackTextBox.Current.Value = filePath.OldValue;
}
private void onCommit(TextBox sender, bool newText)
{
if (!newText) return;
// for now, update these on commit rather than making BeatmapMetadata bindables.
// after switching database engines we can reconsider if switching to bindables is a good direction.
Beatmap.Value.Metadata.Artist = artistTextBox.Current.Value;
Beatmap.Value.Metadata.Title = titleTextBox.Current.Value;
Beatmap.Value.Metadata.AuthorString = creatorTextBox.Current.Value;
Beatmap.Value.BeatmapInfo.Version = difficultyTextBox.Current.Value;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
game?.UnregisterImportHandler(this);
} }
} }
internal class FileChooserLabelledTextBox : LabelledTextBox internal class SetupScreenHeader : OverlayHeader
{ {
public Container Target; protected override OverlayTitle CreateTitle() => new SetupScreenTitle();
private readonly IBindable<FileInfo> currentFile = new Bindable<FileInfo>(); private class SetupScreenTitle : OverlayTitle
public FileChooserLabelledTextBox()
{ {
currentFile.BindValueChanged(onFileSelected); public SetupScreenTitle()
}
private void onFileSelected(ValueChangedEvent<FileInfo> file)
{
if (file.NewValue == null)
return;
Target.Clear();
Current.Value = file.NewValue.FullName;
}
protected override OsuTextBox CreateTextBox() =>
new FileChooserOsuTextBox
{ {
Anchor = Anchor.Centre, Title = "beatmap setup";
Origin = Anchor.Centre, Description = "change general settings of your beatmap";
RelativeSizeAxes = Axes.X, IconTexture = "Icons/Hexacons/social";
CornerRadius = CORNER_RADIUS,
OnFocused = DisplayFileChooser
};
public void DisplayFileChooser()
{
Target.Child = new FileSelector(validFileExtensions: SetupScreen.AudioExtensions)
{
RelativeSizeAxes = Axes.X,
Height = 400,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
CurrentFile = { BindTarget = currentFile }
};
}
internal class FileChooserOsuTextBox : OsuTextBox
{
public Action OnFocused;
protected override void OnFocus(FocusEvent e)
{
OnFocused?.Invoke();
base.OnFocus(e);
GetContainingInputManager().TriggerFocusContention(this);
} }
} }
} }

View File

@ -0,0 +1,42 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osuTK;
namespace osu.Game.Screens.Edit.Setup
{
internal class SetupSection : Container
{
private readonly FillFlowContainer flow;
[Resolved]
protected OsuColour Colours { get; private set; }
[Resolved]
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
protected override Container<Drawable> Content => flow;
public SetupSection()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding(10);
InternalChild = flow = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(20),
Direction = FillDirection.Vertical,
};
}
}
}