Добавил музыкальную очередь в музыкальный автомат
This commit is contained in:
@@ -47,6 +47,16 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
|
||||
|
||||
_menu.OnSongSelected += SelectSong;
|
||||
|
||||
_menu.OnSongQueueAdd += songId =>
|
||||
{
|
||||
SendMessage(new JukeboxAddQueueMessage(songId));
|
||||
};
|
||||
|
||||
_menu.OnQueueRemove += index =>
|
||||
{
|
||||
SendMessage(new JukeboxRemoveQueueMessage(index));
|
||||
};
|
||||
|
||||
_menu.SetTime += SetTime;
|
||||
PopulateMusic();
|
||||
Reload();
|
||||
@@ -65,17 +75,24 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
|
||||
if (_protoManager.TryIndex(jukebox.SelectedSongId, out var songProto))
|
||||
{
|
||||
var length = EntMan.System<AudioSystem>().GetAudioLength(songProto.Path.Path.ToString());
|
||||
_menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds);
|
||||
_menu.SetSelectedSong(songProto.ID, (float) length.TotalSeconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
_menu.SetSelectedSong(string.Empty, 0f);
|
||||
_menu.SetSelectedSong(null, 0f);
|
||||
}
|
||||
|
||||
_menu.PopulateQueue(jukebox.SongIdQueue);
|
||||
_menu.SetIsPlaying(EntMan.System<AudioSystem>().IsPlaying(jukebox.AudioStream));
|
||||
}
|
||||
|
||||
public void PopulateMusic()
|
||||
{
|
||||
_menu?.Populate(_protoManager.EnumeratePrototypes<JukeboxPrototype>());
|
||||
if (_menu == null || !EntMan.TryGetComponent(Owner, out JukeboxComponent? jukebox))
|
||||
return;
|
||||
|
||||
_menu.Populate(_protoManager.EnumeratePrototypes<JukeboxPrototype>());
|
||||
_menu.PopulateQueue(jukebox.SongIdQueue);
|
||||
}
|
||||
|
||||
public void SelectSong(ProtoId<JukeboxPrototype> songid)
|
||||
|
||||
10
Content.Client/Audio/Jukebox/JukeboxEntry.xaml
Normal file
10
Content.Client/Audio/Jukebox/JukeboxEntry.xaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
Orientation="Horizontal"
|
||||
HorizontalExpand="True"
|
||||
>
|
||||
<Label Name="SongName" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
<Button Name="PlayButton" StyleClasses="OpenRight" Text="{Loc 'jukebox-menu-buttonplay'}" />
|
||||
<Button Name="StopButton" StyleClasses="OpenLeft" Text="{Loc 'jukebox-menu-buttonstop'}" />
|
||||
<Button Name="RemoveButton" Text="{Loc 'jukebox-menu-buttonremove'}" />
|
||||
<Button Name="QueueButton" StyleClasses="OpenLeft" Text="{Loc 'jukebox-menu-buttonqueue'}" />
|
||||
</BoxContainer>
|
||||
127
Content.Client/Audio/Jukebox/JukeboxEntry.xaml.cs
Normal file
127
Content.Client/Audio/Jukebox/JukeboxEntry.xaml.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Content.Shared.Audio.Jukebox;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
|
||||
namespace Content.Client.Audio.Jukebox;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class JukeboxEntry : BoxContainer
|
||||
{
|
||||
private JukeboxPrototype? _song;
|
||||
private bool _playPauseState = true;
|
||||
public bool PlayPauseState
|
||||
{
|
||||
get {return _playPauseState;}
|
||||
set {
|
||||
_playPauseState = value;
|
||||
UpdateLabel();
|
||||
}
|
||||
}
|
||||
|
||||
private JukeboxEntryType _entryType;
|
||||
public JukeboxEntryType EntryType
|
||||
{
|
||||
get {return _entryType;}
|
||||
set {
|
||||
_entryType = value;
|
||||
Buttons();
|
||||
}
|
||||
}
|
||||
|
||||
public JukeboxEntry()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public JukeboxEntry(JukeboxPrototype? song) : this()
|
||||
{
|
||||
SetSong(song);
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public void SetSong(JukeboxPrototype? song)
|
||||
{
|
||||
_song = song;
|
||||
|
||||
if (song == null)
|
||||
{
|
||||
Buttons();
|
||||
return;
|
||||
}
|
||||
|
||||
SongName.Text = song.Name;
|
||||
|
||||
Buttons();
|
||||
}
|
||||
|
||||
public void SetOnPressedPlay(Action<JukeboxPrototype?, bool, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
PlayButton.OnPressed += args => {
|
||||
if (_entryType == JukeboxEntryType.Current)
|
||||
{
|
||||
_playPauseState = !_playPauseState;
|
||||
UpdateLabel();
|
||||
}
|
||||
func(_song, _playPauseState, args);
|
||||
};
|
||||
}
|
||||
|
||||
public void SetOnPressedQueue(Action<JukeboxPrototype?, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
QueueButton.OnPressed += args => {
|
||||
func(_song, args);
|
||||
};
|
||||
}
|
||||
|
||||
public void SetOnPressedStop(Action<BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
StopButton.OnPressed += func;
|
||||
}
|
||||
|
||||
public void SetOnPressedRemove(Action<JukeboxEntry, BaseButton.ButtonEventArgs>? func)
|
||||
{
|
||||
if (func == null)
|
||||
return;
|
||||
|
||||
RemoveButton.OnPressed += args => {
|
||||
func(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
private void Buttons()
|
||||
{
|
||||
PlayButton.Visible = _song != null && (_entryType == JukeboxEntryType.List || _entryType == JukeboxEntryType.Current);
|
||||
StopButton.Visible = _song != null && _entryType == JukeboxEntryType.Current;
|
||||
RemoveButton.Visible = _song != null && _entryType == JukeboxEntryType.Queue;
|
||||
QueueButton.Visible = _song != null && _entryType == JukeboxEntryType.List;
|
||||
}
|
||||
|
||||
private void UpdateLabel()
|
||||
{
|
||||
if (!_playPauseState)
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonplay");
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonpause");
|
||||
}
|
||||
}
|
||||
|
||||
public enum JukeboxEntryType
|
||||
{
|
||||
List,
|
||||
Queue,
|
||||
Current,
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
<ui:FancyWindow xmlns="https://spacestation14.io" xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:jb="clr-namespace:Content.Client.Audio.Jukebox"
|
||||
SetSize="400 500" Title="{Loc 'jukebox-menu-title'}">
|
||||
<BoxContainer Margin="4 0" Orientation="Vertical">
|
||||
<ItemList Name="MusicList" SelectMode="Button" Margin="3 3 3 3"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="SongSelected" Text="{Loc 'jukebox-menu-selectedsong'}" />
|
||||
<Label Name="SongName" Text="---" />
|
||||
<Slider Name="PlaybackSlider" HorizontalExpand="True" />
|
||||
<Label Text="{Loc 'jukebox-menu-songs'}"/>
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" Margin="13 3 3 3">
|
||||
<BoxContainer Name="MusicList" Orientation="Vertical"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
</ScrollContainer>
|
||||
<Label Text="{Loc 'jukebox-menu-queue'}"/>
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" Margin="13 3 3 3">
|
||||
<BoxContainer Name="MusicListQueue" Orientation="Vertical"
|
||||
HorizontalExpand="True" VerticalExpand="True" SizeFlagsStretchRatio="8"/>
|
||||
</ScrollContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Name="SongSelected" Text="{Loc 'jukebox-menu-selectedsong-none'}" />
|
||||
<BoxContainer HorizontalExpand="True"/>
|
||||
<Label Name="DurationLabel" Text="---" />
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"
|
||||
VerticalExpand="False" SizeFlagsStretchRatio="1">
|
||||
<Button Name="PlayButton" Text="{Loc 'jukebox-menu-buttonplay'}" />
|
||||
<Button Name="StopButton" Text="{Loc 'jukebox-menu-buttonstop'}" />
|
||||
<Label Name="DurationLabel" Text="00:00 / 00:00" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
<Slider Name="PlaybackSlider" Visible="false" HorizontalExpand="True" />
|
||||
<jb:JukeboxEntry Name="CurrentSong" Visible="false" EntryType="Current"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ui:FancyWindow>
|
||||
|
||||
@@ -14,12 +14,10 @@ namespace Content.Client.Audio.Jukebox;
|
||||
public sealed partial class JukeboxMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
private AudioSystem _audioSystem;
|
||||
|
||||
/// <summary>
|
||||
/// Are we currently 'playing' or paused for the play / pause button.
|
||||
/// </summary>
|
||||
private bool _playState;
|
||||
|
||||
/// <summary>
|
||||
/// True if playing, false if paused.
|
||||
@@ -29,6 +27,9 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
public event Action<ProtoId<JukeboxPrototype>>? OnSongSelected;
|
||||
public event Action<float>? SetTime;
|
||||
|
||||
public event Action<ProtoId<JukeboxPrototype>>? OnSongQueueAdd;
|
||||
public event Action<int>? OnQueueRemove;
|
||||
|
||||
private EntityUid? _audio;
|
||||
|
||||
private float _lockTimer;
|
||||
@@ -39,28 +40,18 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
IoCManager.InjectDependencies(this);
|
||||
_audioSystem = _entManager.System<AudioSystem>();
|
||||
|
||||
MusicList.OnItemSelected += args =>
|
||||
{
|
||||
var entry = MusicList[args.ItemIndex];
|
||||
|
||||
if (entry.Metadata is not string juke)
|
||||
return;
|
||||
|
||||
OnSongSelected?.Invoke(juke);
|
||||
};
|
||||
|
||||
PlayButton.OnPressed += args =>
|
||||
{
|
||||
OnPlayPressed?.Invoke(!_playState);
|
||||
};
|
||||
|
||||
StopButton.OnPressed += args =>
|
||||
CurrentSong.SetOnPressedStop(args =>
|
||||
{
|
||||
OnStopPressed?.Invoke();
|
||||
};
|
||||
});
|
||||
|
||||
CurrentSong.SetOnPressedPlay((song, playPauseState, args) =>
|
||||
{
|
||||
OnPlayPressed?.Invoke(playPauseState);
|
||||
});
|
||||
|
||||
PlaybackSlider.OnReleased += PlaybackSliderKeyUp;
|
||||
|
||||
SetPlayPauseButton(_audioSystem.IsPlaying(_audio), force: true);
|
||||
}
|
||||
|
||||
public JukeboxMenu(AudioSystem audioSystem)
|
||||
@@ -84,33 +75,43 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
/// </summary>
|
||||
public void Populate(IEnumerable<JukeboxPrototype> jukeboxProtos)
|
||||
{
|
||||
MusicList.Clear();
|
||||
MusicList.RemoveAllChildren();
|
||||
|
||||
foreach (var entry in jukeboxProtos)
|
||||
{
|
||||
MusicList.AddItem(entry.Name, metadata: entry.ID);
|
||||
// MusicList.AddItem(entry.Name, metadata: entry.ID);
|
||||
var songControl = new JukeboxEntry(entry) {EntryType = JukeboxEntry.JukeboxEntryType.List};
|
||||
songControl.SetOnPressedPlay((song, _, args) =>
|
||||
{
|
||||
if (song == null)
|
||||
return;
|
||||
OnSongSelected?.Invoke(song.ID);
|
||||
OnPlayPressed?.Invoke(true);
|
||||
});
|
||||
|
||||
songControl.SetOnPressedQueue((song, args) =>
|
||||
{
|
||||
if (song == null)
|
||||
return;
|
||||
OnSongQueueAdd?.Invoke(song.ID);
|
||||
});
|
||||
|
||||
MusicList.AddChild(songControl);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPlayPauseButton(bool playing, bool force = false)
|
||||
public void SetSelectedSong(ProtoId<JukeboxPrototype>? song, float length)
|
||||
{
|
||||
if (_playState == playing && !force)
|
||||
if (song == null)
|
||||
return;
|
||||
|
||||
_playState = playing;
|
||||
|
||||
if (playing)
|
||||
{
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonpause");
|
||||
if (!_prototype.TryIndex(song, out var songProto))
|
||||
return;
|
||||
}
|
||||
|
||||
PlayButton.Text = Loc.GetString("jukebox-menu-buttonplay");
|
||||
}
|
||||
|
||||
public void SetSelectedSong(string name, float length)
|
||||
{
|
||||
SetSelectedSongText(name);
|
||||
SongSelected.Text = Loc.GetString("jukebox-menu-selectedsong");
|
||||
PlaybackSlider.Visible = true;
|
||||
CurrentSong.Visible = true;
|
||||
CurrentSong.SetSong(songProto);
|
||||
PlaybackSlider.MaxValue = length;
|
||||
PlaybackSlider.SetValueWithoutEvent(0);
|
||||
}
|
||||
@@ -145,18 +146,34 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
PlaybackSlider.SetValueWithoutEvent(0f);
|
||||
}
|
||||
|
||||
SetPlayPauseButton(_audioSystem.IsPlaying(_audio, audio));
|
||||
}
|
||||
|
||||
public void SetSelectedSongText(string? text)
|
||||
/// <summary>
|
||||
/// Re-populates the queue with avaiable jukebox prototypes.
|
||||
/// </summary>
|
||||
public void PopulateQueue(IEnumerable<ProtoId<JukeboxPrototype>> queue)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
MusicListQueue.RemoveAllChildren();
|
||||
int i = 0;
|
||||
foreach (var song in queue)
|
||||
{
|
||||
SongName.Text = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
SongName.Text = "---";
|
||||
if (!_prototype.TryIndex(song, out var songProto))
|
||||
continue;
|
||||
|
||||
i += 1;
|
||||
var songControl = new JukeboxEntry(songProto) {EntryType = JukeboxEntry.JukeboxEntryType.Queue};
|
||||
MusicListQueue.AddChild(songControl);
|
||||
|
||||
songControl.SetOnPressedRemove((source, args) =>
|
||||
{
|
||||
int index = source.GetPositionInParent();
|
||||
OnQueueRemove?.Invoke(index);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIsPlaying(bool isPlaying)
|
||||
{
|
||||
CurrentSong.PlayPauseState = isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
|
||||
var query = AllEntityQuery<JukeboxComponent, UserInterfaceComponent>();
|
||||
|
||||
while (query.MoveNext(out _, out var ui))
|
||||
while (query.MoveNext(out var uid, out var jukebox, out var ui))
|
||||
{
|
||||
if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) ||
|
||||
baseBui is not JukeboxBoundUserInterface bui)
|
||||
@@ -43,6 +43,24 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj.Removed?.TryGetValue(typeof(JukeboxPrototype), out var removed) ?? false)
|
||||
{
|
||||
var list = new List<ProtoId<JukeboxPrototype>>();
|
||||
while (jukebox.SongIdQueue.Count > 0)
|
||||
{
|
||||
var next = jukebox.SongIdQueue.Dequeue();
|
||||
if (removed.Contains(next))
|
||||
continue;
|
||||
|
||||
|
||||
list.Add(next);
|
||||
}
|
||||
foreach (var song in list)
|
||||
{
|
||||
jukebox.SongIdQueue.Enqueue(song);
|
||||
}
|
||||
}
|
||||
|
||||
bui.PopulateMusic();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user