244 lines
7.6 KiB
C#
244 lines
7.6 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Client.UserInterface.Controls;
|
|
using Content.Shared._DV.QuickPhrase;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Client._DV.AACTablet.UI;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class AACWindow : FancyWindow
|
|
{
|
|
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
|
private readonly List<QuickPhrasePrototype> _phrases;
|
|
private readonly Dictionary<string, List<QuickPhrasePrototype>> _filteredPhrases = new();
|
|
public event Action<List<ProtoId<QuickPhrasePrototype>>>? PhraseButtonPressed;
|
|
public event Action? Typing;
|
|
public event Action? SubmitPressed;
|
|
|
|
private const float SpaceWidth = 10f;
|
|
private const float ParentWidth = 540f;
|
|
private const int ColumnCount = 4;
|
|
|
|
private const int ButtonWidth =
|
|
(int)((ParentWidth - SpaceWidth * 2) / ColumnCount - SpaceWidth * ((ColumnCount - 1f) / ColumnCount));
|
|
|
|
public const int MaxPhrases = 10; // no writing novels
|
|
|
|
private readonly List<ProtoId<QuickPhrasePrototype>> _phraseBuffer = [];
|
|
private readonly List<ProtoId<QuickPhrasePrototype>> _phraseSingle = [];
|
|
|
|
public AACWindow()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
IoCManager.InjectDependencies(this);
|
|
|
|
_phrases = _prototype.EnumeratePrototypes<QuickPhrasePrototype>().ToList();
|
|
_phrases.Sort((a, b) => string.CompareOrdinal(a.Group, b.Group));
|
|
SearchBar.OnTextChanged += FilterSearch;
|
|
SendButton.OnPressed += SendBuffer;
|
|
ClearButton.OnPressed += BackspaceBuffer;
|
|
PopulateGui();
|
|
FilterSearch(null);
|
|
}
|
|
|
|
private void BackspaceBuffer(BaseButton.ButtonEventArgs obj)
|
|
{
|
|
if (_phraseBuffer.Count == 0)
|
|
return;
|
|
|
|
_phraseBuffer.RemoveAt(_phraseBuffer.Count - 1);
|
|
UpdateBufferText();
|
|
Typing?.Invoke();
|
|
}
|
|
|
|
private void UpdateBufferText()
|
|
{
|
|
BufferedString.Text = string.Empty;
|
|
foreach (var phraseId in _phraseBuffer)
|
|
{
|
|
var phrase = _prototype.Index(phraseId);
|
|
BufferedString.Text += Loc.GetString(phrase.Text) + " ";
|
|
}
|
|
}
|
|
|
|
private void SendBuffer(BaseButton.ButtonEventArgs obj)
|
|
{
|
|
PhraseButtonPressed?.Invoke(_phraseBuffer);
|
|
_phraseBuffer.Clear();
|
|
BufferedString.Text = string.Empty;
|
|
SubmitPressed?.Invoke();
|
|
}
|
|
|
|
private void FilterSearch(LineEdit.LineEditEventArgs? obj)
|
|
{
|
|
SearchResults.RemoveAllChildren();
|
|
_filteredPhrases.Clear();
|
|
|
|
var emptySearch = string.IsNullOrEmpty(SearchBar.Text);
|
|
foreach (var phrase in _phrases)
|
|
{
|
|
if (!emptySearch && !Loc.GetString(phrase.Text).Contains(SearchBar.Text, StringComparison.CurrentCultureIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (_filteredPhrases.TryGetValue(phrase.Group, out var group))
|
|
{
|
|
group.Add(phrase);
|
|
}
|
|
else
|
|
{
|
|
_filteredPhrases.Add(phrase.Group, new List<QuickPhrasePrototype> { phrase });
|
|
}
|
|
}
|
|
|
|
foreach (var phraseList in _filteredPhrases.Values)
|
|
{
|
|
phraseList.Sort((a, b) =>
|
|
string.Compare(Loc.GetString(a.Text),
|
|
Loc.GetString(b.Text),
|
|
StringComparison.CurrentCultureIgnoreCase));
|
|
}
|
|
|
|
var boxContainer = CreateBoxContainerForTab(_filteredPhrases);
|
|
SearchResults.AddChild(boxContainer);
|
|
}
|
|
|
|
private void PopulateGui()
|
|
{
|
|
// take ALL phrases and turn them into tabs and groups, so the buttons are sorted and tabbed
|
|
var sortedTabs = _phrases
|
|
.GroupBy(p => p.Tab)
|
|
.OrderBy(g => g.Key)
|
|
.ToDictionary(
|
|
g => g.Key,
|
|
g => g.GroupBy(p => p.Group)
|
|
.OrderBy(gg => gg.Key)
|
|
.ToDictionary(
|
|
gg => gg.Key,
|
|
gg => gg.OrderBy(p => Loc.GetString(p.Text)).ToList()
|
|
)
|
|
);
|
|
|
|
CreateTabContainer(sortedTabs);
|
|
}
|
|
|
|
private void CreateTabContainer(Dictionary<string, Dictionary<string, List<QuickPhrasePrototype>>> sortedTabs)
|
|
{
|
|
foreach (var tab in sortedTabs)
|
|
{
|
|
var tabName = Loc.GetString(tab.Key);
|
|
var boxContainer = CreateBoxContainerForTab(tab.Value);
|
|
var scroll = new ScrollContainer();
|
|
scroll.HScrollEnabled = false;
|
|
scroll.AddChild(boxContainer);
|
|
WindowBody.AddChild(scroll);
|
|
WindowBody.SetTabTitle(WindowBody.ChildCount - 1, tabName);
|
|
}
|
|
}
|
|
|
|
private BoxContainer CreateBoxContainerForTab(Dictionary<string, List<QuickPhrasePrototype>> groups)
|
|
{
|
|
var boxContainer = new BoxContainer
|
|
{
|
|
HorizontalExpand = true,
|
|
Orientation = BoxContainer.LayoutOrientation.Vertical
|
|
};
|
|
|
|
foreach (var group in groups)
|
|
{
|
|
var header = CreateHeaderForGroup(group.Key);
|
|
var buttonContainer = CreateButtonContainerForGroup(group.Value);
|
|
boxContainer.AddChild(header);
|
|
boxContainer.AddChild(buttonContainer);
|
|
}
|
|
|
|
return boxContainer;
|
|
}
|
|
|
|
private static Label CreateHeaderForGroup(string groupName)
|
|
{
|
|
var header = new Label
|
|
{
|
|
HorizontalExpand = true,
|
|
Text = groupName,
|
|
Margin = new Thickness(10, 10, 10, 0),
|
|
StyleClasses = { "LabelBig" }
|
|
};
|
|
|
|
return header;
|
|
}
|
|
|
|
private GridContainer CreateButtonContainerForGroup(List<QuickPhrasePrototype> phrases)
|
|
{
|
|
var buttonContainer = CreateButtonContainer();
|
|
foreach (var phrase in phrases)
|
|
{
|
|
var text = Loc.GetString(phrase.Text);
|
|
var button = CreatePhraseButton(text, phrase.StyleClass);
|
|
button.OnPressed += _ => OnPhraseButtonPressed(phrase);
|
|
buttonContainer.AddChild(button);
|
|
}
|
|
return buttonContainer;
|
|
}
|
|
|
|
private static GridContainer CreateButtonContainer()
|
|
{
|
|
var buttonContainer = new GridContainer
|
|
{
|
|
Margin = new Thickness(10),
|
|
Columns = ColumnCount
|
|
};
|
|
|
|
return buttonContainer;
|
|
}
|
|
|
|
private static Button CreatePhraseButton(string text, string styleClass)
|
|
{
|
|
var phraseButton = new Button
|
|
{
|
|
Access = AccessLevel.Public,
|
|
MaxSize = new Vector2(ButtonWidth, ButtonWidth),
|
|
ClipText = false,
|
|
HorizontalExpand = true,
|
|
StyleClasses = { styleClass }
|
|
};
|
|
|
|
var buttonLabel = new RichTextLabel
|
|
{
|
|
Margin = new Thickness(0, 5),
|
|
StyleClasses = { "WhiteText" }
|
|
};
|
|
|
|
buttonLabel.SetMessage(text);
|
|
phraseButton.AddChild(buttonLabel);
|
|
return phraseButton;
|
|
}
|
|
|
|
private void OnPhraseButtonPressed(ProtoId<QuickPhrasePrototype> phraseId)
|
|
{
|
|
if (ShouldBuffer.Pressed)
|
|
{
|
|
// there's no user feedback but you shouldn't be writing novels anyway
|
|
if (_phraseBuffer.Count >= MaxPhrases)
|
|
return;
|
|
|
|
_phraseBuffer.Add(phraseId);
|
|
UpdateBufferText();
|
|
Typing?.Invoke();
|
|
}
|
|
else
|
|
{
|
|
_phraseSingle.Clear();
|
|
_phraseSingle.Add(phraseId);
|
|
PhraseButtonPressed?.Invoke(_phraseSingle);
|
|
SubmitPressed?.Invoke();
|
|
}
|
|
}
|
|
}
|