CatStation/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs
Ataman 0c5b250f03
Instrument UI overhaul (#41604)
* Added base type for UI panels of MIDI input sources.

* Renamed BandMenu into BandMidiSource.

* Implemented the UI overhaul, skipping channels dialog functionality for now.

* Refactored for conventions and reordered type members.
Got rid of SetInstrument/ClearInstrument again.

* Decreased background opacity for UnavailableOverlay to improve readability.

* Localization

* Added text to InputMidiSource so players know what it does.

* Changed window MinSize to SetSize. Allows players to reduce window size if desired.

* Improved button looks by adding style classes.

* cleanup

* leftover cleanup

* Reverted fetching InstrumentSystem via IoCManager (crashes it, woops).

* added filter bar to file list

* refactored almost all system/manager interaction into instrument BUI

* text changed for instruments-component-menu-input-notice-label

* fixed InstrumentBoundUserInterface.Dispose not unsubscribing from everything

* minor cleanup

* finished configuration menu & cleanup

* Comments and fixes for InstrumentMidiSourceBase

* Fixed RA0051

* Removed unncecessary null check

* Added methods for accessing the selected track.

* Limited depth of search for instrument master to prevent deadlock.

* Cached system access

* Storing midis asynchronously

* Actual MIDI data now only loaded before playback.

* async removed from InstrumentBoundUserInterface.LoadStoredUserMidis

* Replaced GetComponent calls with TryGetComponent

* Localized MIDI playback track timer

* Searching for next track using raw index now

* Fixed CS0168

* XML comments, minor fixes and disabled MIDI library management while a track is playing.

* removed timers with simple watchdog and switched to MidiFileCollectionManager

* Missed one (timer)

* Changed access for MidiFileCollectionManager.UserMidiDirectory field to public.

* Added instrument config control for MIDI collection utilities.

* redesigned instrument config menu

* Removed rename function, updated adding implementation

* more redesigns

* fixed _isMidiFileDialogueWindowOpen not resetting correctly in certain cases.

* file scoped namespaces

* replaced EntityUid with Entity<InstrumentComponent>

* if spaces

* returning Tooltip instead of Control

* replaced SetEntity with public field

* readonly system fields

* InstrumentMenu MinSize

* xml comment for InstrumentMidiSourceBase

* small refactor

* more cleanup

* TryGetComponent to GetComponent on Open()

* more formatting issues

* switched to [Dependency] for systems

* playback improvements

* disable playback button if no file selected and playing

* activating shuffle now selects track if none is selected

* rearranged playback buttons

* channels overhauled

* Play/Stop label to Play only

* Removed all channel on/off

* Program now default channel name display selection

* improved RemoveButton.Disable behavior

* channels now toggable by clicking anywhere

* Shuffle no longer selects already selected track.

* Loop & Shuffle no longer both selectable at once

* minor improvements to channel item visuals

* minor channel toggle fixes

* xml docs & code cleanup

* `RefreshBandRequest` now sent automatically when band source becomes visible

* converted 5 items tuple to MidiChannelInfo record

* added markup support to instrument menu configuration header

* added note to midi channels config header explaining update behavior.
2026-07-26 16:50:28 +00:00

144 lines
4.8 KiB
C#

using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client.Instruments.UI;
[GenerateTypedNameReferences]
public sealed partial class InstrumentMenu : FancyWindow
{
private InstrumentMidiSourceBase? _currentMode;
public InstrumentMenu()
{
RobustXamlLoader.Load(this);
var styleBox = new StyleBoxFlat
{
BorderThickness = new Thickness(0),
Padding = new Thickness(10),
};
MainTabContainer.PanelStyleBoxOverride = styleBox;
MainTabContainer.SetTabTitle(0, Loc.GetString("instruments-component-menu-play-tab-title"));
MainTabContainer.SetTabTitle(1, Loc.GetString("instruments-component-menu-config-tab-title"));
}
protected override void ExitedTree()
{
base.ExitedTree();
_currentMode?.Disable();
}
/// <summary>
/// Registers the passed midi source controls as children of this instrument menu and creates a button
/// for each one on the left hand side of the menu.
/// </summary>
/// <param name="sources">The sources to be registered</param>
public void SetupSources(params InstrumentMidiSourceBase[] sources)
{
var group = new ButtonGroup();
for (var i = 0; i < sources.Length; i++)
{
var source = sources[i];
var button = new Button();
button.Text = source.ButtonName;
button.Group = group;
button.OnPressed += _ => { SwitchMode(source); };
MidiSourceButtonsBoxContainer.Children.Add(button);
MidiSourcesContainer.Children.Add(source);
source.VerticalExpand = true;
source.HorizontalExpand = true;
source.Visible = false;
// Set nicer style classes depending on button position.
if (i == 0)
{
button.Pressed = true;
button.StyleClasses.Add("OpenLeft");
}
else if (i == sources.Length - 1)
{
button.StyleClasses.Add("OpenRight");
}
else
{
button.StyleClasses.Add("OpenBoth");
}
}
}
/// <summary>
/// Takes the given control and registers it as an option for the configuration tab control.
/// </summary>
/// <param name="name">The string to display on the tab header for this configuration.</param>
/// <param name="ctrl">The control used for this configuration.</param>
public void AddConfigurationControl(string name, Control ctrl)
{
var formatted = new FormattedMessage();
var styleBox = new StyleBoxFlat
{
BorderColor = Color.FromHex("#3D4059"),
BorderThickness = new Thickness(2),
};
var panel = new PanelContainer
{
PanelOverride = styleBox,
Margin = new Thickness(0, 0, 0, 10),
};
var header = new RichTextLabel
{
StyleClasses = { StyleClass.LabelKeyText },
Margin = new Thickness(10, 0, 0, 0),
};
ctrl.VerticalExpand = true;
ctrl.Margin = new Thickness(5);
formatted.AddMarkupOrThrow($"[bold]{name}[/bold]");
header.SetMessage(formatted, Color.FromHex("#A88B5E"));
panel.AddChild(ctrl);
ConfigurationItemsContainer.AddChild(header);
ConfigurationItemsContainer.AddChild(panel);
}
/// <summary>
/// Disables & hides the currently active source control, then enables & shows the given one.
/// </summary>
/// <param name="source">The source control to enable.</param>
/// <remarks>The given source must be registered first using the <see cref="SetupSources" /> function.</remarks>
public void SwitchMode(InstrumentMidiSourceBase source)
{
_currentMode?.Disable();
_currentMode = source;
_currentMode.Enable();
}
/// <summary>
/// When true, overlays the menu with a notice that MIDI is currently not available.
/// </summary>
/// <param name="available">Set to true when MIDI is available.</param>
/// <remarks>This should be set to false when MIDI playback is not available on the system.</remarks>
public void SetMidiAvailability(bool available)
{
UnavailableOverlay.Visible = !available;
}
/// <summary>
/// Takes an entity with an <see cref="InstrumentComponent" /> and displays its sprite on the left hand side.
/// </summary>
/// <param name="entity">The entity to display.</param>
public void SetInstrument(Entity<InstrumentComponent> entity)
{
InstrumentSpriteView.SetEntity(entity);
}
}