-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Languages #43
Languages #43
Changes from 7 commits
da76123
a95f105
728e9b1
113826b
6bdc514
3d86f02
bf80a15
c65c1d3
c61e061
0b7dd07
54b15c1
f3b2daa
381eea1
6f841fb
cdb786c
f9dcd71
4bc2c46
076bfc3
7dff567
a0d8c08
d14461e
55794de
4c3724d
e819a63
ec92c56
937a4d9
21dd8dd
f6d46f8
1baab28
c1287b8
ba7d807
1618f20
c10d283
0983aa7
b3ad259
041ef46
7452487
2b3a807
a938832
e66df36
c507898
70987a9
5ce48b2
d5d51b6
b47718d
52c4566
d2ca520
d873884
8af1830
5300226
93e7218
873ab05
a7fefa4
b5a6013
a4ecd2b
875cf7b
5201873
96e1c0a
7c2621b
5023cc4
38060c9
9f6ee28
54dee4f
b75939c
87a0a87
d935e80
6234be8
ec9116a
afdb7ce
932bc29
90f3588
f2adcee
f5e8bca
c25d2ec
566d861
146c32f
9cb5950
f526f0a
0fa806c
dea18f0
e0d65d4
a85ed4d
e23dabe
f336f5a
5ebbbc0
b9850d8
19697bb
789cf4e
1d7d5d2
f6f6679
c4cec66
7581981
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<DefaultWindow xmlns="https://spacestation14.io" | ||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls" | ||
Title="a" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bad place holder title. You should also be able to embed the localization call for the title directly in here rather than in the system, see other UI. |
||
SetSize="300 300"> | ||
<BoxContainer Orientation="Vertical" SeparationOverride="4" MinWidth="150"> | ||
<PanelContainer Name="CurrentLanguageContainer" Access="Public" StyleClasses="PdaBorderRect"> | ||
<Label Name="CurrentLanguageLabel" Access="Public" Text="Current Language:" HorizontalExpand="True"></Label> | ||
</PanelContainer> | ||
|
||
<ui:HLine></ui:HLine> | ||
|
||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="False" VScrollEnabled="True" MinHeight="50"> | ||
<BoxContainer Name="OptionsList" Access="Public" HorizontalExpand="True" SeparationOverride="2" Orientation="Vertical"> | ||
<!-- The rest here is generated programmatically --> | ||
</BoxContainer> | ||
</ScrollContainer> | ||
</BoxContainer> | ||
</DefaultWindow> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
using Content.Client.Language.Systems; | ||
using Content.Shared.Language; | ||
using Content.Shared.Language.Systems; | ||
using Robust.Client.AutoGenerated; | ||
using Robust.Client.UserInterface.Controls; | ||
using Robust.Client.UserInterface.CustomControls; | ||
using Robust.Client.UserInterface.XAML; | ||
using Robust.Shared.Console; | ||
using Robust.Shared.Utility; | ||
using static Content.Shared.Language.Systems.SharedLanguageSystem; | ||
|
||
namespace Content.Client.Language; | ||
|
||
[GenerateTypedNameReferences] | ||
public sealed partial class LanguageMenuWindow : DefaultWindow | ||
{ | ||
private readonly LanguageSystem _clientLanguageSystem; | ||
private readonly List<EntryState> _entries = new(); | ||
|
||
public LanguageMenuWindow() | ||
{ | ||
RobustXamlLoader.Load(this); | ||
_clientLanguageSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<LanguageSystem>(); | ||
|
||
Title = Loc.GetString("language-menu-window-title"); | ||
} | ||
|
||
public void UpdateState(string currentLanguage, List<string> spokenLanguages) | ||
{ | ||
var langName = LanguagePrototype.GetLocalizedName(currentLanguage); | ||
CurrentLanguageLabel.Text = Loc.GetString("language-menu-current-language", ("language", langName ?? "<error>")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couple notes, first off, this seems very strange when the name can be accessed directly through the property. Furthermore, this doesn't need to be validated with '' since GetString will always return a string, it just may be the same one you gave it. Loc.TryGetString can return null, but not GetString. I have only just realized you're using it as a static. Ah. Let me rethink that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace line 30 with resolving the prototype with the ID we have and then get name from prototype. |
||
|
||
OptionsList.RemoveAllChildren(); | ||
_entries.Clear(); | ||
|
||
foreach (var language in spokenLanguages) | ||
{ | ||
AddLanguageEntry(language); | ||
} | ||
|
||
// Disable the button for the currently chosen language | ||
foreach (var entry in _entries) | ||
{ | ||
if (entry.button != null) | ||
entry.button.Disabled = entry.language == currentLanguage; | ||
} | ||
} | ||
|
||
private void AddLanguageEntry(string language) | ||
{ | ||
var proto = _clientLanguageSystem.GetLanguage(language); | ||
var state = new EntryState { language = language }; | ||
|
||
var container = new BoxContainer(); | ||
container.Orientation = BoxContainer.LayoutOrientation.Vertical; | ||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Create and add a header with the name and the button to select the language | ||
{ | ||
var header = new BoxContainer(); | ||
header.Orientation = BoxContainer.LayoutOrientation.Horizontal; | ||
|
||
header.Orientation = BoxContainer.LayoutOrientation.Horizontal; | ||
header.HorizontalExpand = true; | ||
header.SeparationOverride = 2; | ||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
var name = new Label(); | ||
name.Text = proto?.LocalizedName ?? "<error>"; | ||
name.MinWidth = 50; | ||
name.HorizontalExpand = true; | ||
|
||
var button = new Button(); | ||
button.Text = "Choose"; | ||
button.OnPressed += _ => OnLanguageChosen(language); | ||
state.button = button; | ||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
FoxxoTrystan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
header.AddChild(name); | ||
header.AddChild(button); | ||
|
||
container.AddChild(header); | ||
} | ||
|
||
// Create and add a collapsible description | ||
{ | ||
var body = new CollapsibleBody(); | ||
body.HorizontalExpand = true; | ||
body.Margin = new Thickness(4f, 4f); | ||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
var description = new RichTextLabel(); | ||
description.SetMessage(proto?.LocalizedDescription ?? "<error>"); | ||
description.HorizontalExpand = true; | ||
|
||
body.AddChild(description); | ||
|
||
var collapser = new Collapsible(Loc.GetString("language-menu-description-header"), body); | ||
collapser.Orientation = BoxContainer.LayoutOrientation.Vertical; | ||
collapser.HorizontalExpand = true; | ||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
container.AddChild(collapser); | ||
} | ||
|
||
// Before adding, wrap the new container in a PanelContainer to give it a distinct look | ||
var wrapper = new PanelContainer(); | ||
wrapper.StyleClasses.Add("PdaBorderRect"); | ||
|
||
wrapper.AddChild(container); | ||
OptionsList.AddChild(wrapper); | ||
|
||
_entries.Add(state); | ||
} | ||
|
||
private void OnLanguageChosen(string id) | ||
{ | ||
var proto = _clientLanguageSystem.GetLanguage(id); | ||
if (proto != null) | ||
_clientLanguageSystem.RequestSetLanguage(proto); | ||
} | ||
|
||
Mnemotechnician marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private struct EntryState | ||
{ | ||
public string language; | ||
public Button? button; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using System.Linq; | ||
using System.Numerics; | ||
using Content.Client.Language.Systems; | ||
using Content.Client.UserInterface.Systems.Chat.Controls; | ||
using Content.Client.UserInterface.Systems.Language; | ||
using Content.Shared.Language; | ||
using Robust.Client.UserInterface; | ||
using Robust.Shared.Utility; | ||
|
||
namespace Content.Client.Language.Systems.Chat.Controls; | ||
|
||
// Mostly copied from ChannelSelectorButton | ||
public sealed class LanguageSelectorButton : ChatPopupButton<LanguageSelectorPopup> | ||
{ | ||
public LanguagePrototype? SelectedLanguage { get; private set; } | ||
|
||
private const int SelectorDropdownOffset = 38; | ||
|
||
public LanguageSelectorButton() | ||
{ | ||
Name = "LanguageSelector"; | ||
|
||
Popup.Selected += Select; | ||
|
||
if (Popup.FirstLanguage is { } firstSelector) | ||
{ | ||
Select(firstSelector); | ||
} | ||
|
||
IoCManager.Resolve<IUserInterfaceManager>().GetUIController<LanguageMenuUIController>().LanguagesUpdatedHook += UpdateLanguage; | ||
} | ||
|
||
private void UpdateLanguage((string current, List<string> spoken, List<string> understood) args) | ||
{ | ||
Popup.SetLanguages(args.spoken); | ||
|
||
// Kill me please | ||
SelectedLanguage = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<LanguageSystem>().GetLanguage(args.current); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make a variable for this system and cache it in the constructor when the UI starts instead of resolving it every time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to do that before and it turned out that UI is created before systems are loaded, where'd you suggest caching it to avoid that? |
||
Text = LanguageSelectorName(SelectedLanguage!); | ||
} | ||
|
||
protected override UIBox2 GetPopupPosition() | ||
{ | ||
var globalLeft = GlobalPosition.X; | ||
var globalBot = GlobalPosition.Y + Height; | ||
return UIBox2.FromDimensions( | ||
new Vector2(globalLeft, globalBot), | ||
new Vector2(SizeBox.Width, SelectorDropdownOffset)); | ||
} | ||
|
||
public void Select(LanguagePrototype language) | ||
{ | ||
if (Popup.Visible) | ||
{ | ||
Popup.Close(); | ||
} | ||
|
||
if (SelectedLanguage == language) | ||
return; | ||
SelectedLanguage = language; | ||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<LanguageSystem>().RequestSetLanguage(language); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
|
||
Text = LanguageSelectorName(language); | ||
} | ||
|
||
public static string LanguageSelectorName(LanguagePrototype language, bool full = false) | ||
{ | ||
var name = language.LocalizedName; | ||
|
||
// if the language name is short enough, just return it | ||
if (full || name.Length < 5) | ||
return name; | ||
|
||
// If the language name is multi-word, collect first letters and capitalize them | ||
if (name.Contains(' ')) | ||
{ | ||
var result = name | ||
.Split(" ") | ||
.Select(it => it.FirstOrNull()) | ||
.Where(it => it != null) | ||
.Select(it => char.ToUpper(it!.Value)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't love the name 'it' for this, makes it even harder to read :P |
||
|
||
return new string(result.ToArray()); | ||
} | ||
|
||
// Alternatively, take the first 5 letters | ||
return name[..5]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using Content.Client.Stylesheets; | ||
using Content.Client.UserInterface.Systems.Chat; | ||
using Content.Client.UserInterface.Systems.Chat.Controls; | ||
using Content.Shared.Chat; | ||
using Content.Shared.Language; | ||
using Robust.Client.UserInterface.Controls; | ||
|
||
namespace Content.Client.Language.Systems.Chat.Controls; | ||
|
||
// Mostly copied from ChannelSelectorItemButton | ||
public sealed class LanguageSelectorItemButton : Button | ||
{ | ||
public readonly LanguagePrototype Language; | ||
|
||
public bool IsHidden => Parent == null; | ||
|
||
public LanguageSelectorItemButton(LanguagePrototype language) | ||
{ | ||
Language = language; | ||
AddStyleClass(StyleNano.StyleClassChatChannelSelectorButton); | ||
|
||
Text = LanguageSelectorButton.LanguageSelectorName(language, full: true); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using Content.Client.Language.Systems; | ||
using Content.Client.UserInterface.Systems.Language; | ||
using Content.Shared.Language; | ||
using Robust.Client.UserInterface; | ||
using Robust.Client.UserInterface.Controls; | ||
using static Robust.Client.UserInterface.Controls.BaseButton; | ||
|
||
namespace Content.Client.Language.Systems.Chat.Controls; | ||
|
||
// Mostly copied from LanguageSelectorPopup | ||
public sealed class LanguageSelectorPopup : Popup | ||
{ | ||
private readonly BoxContainer _channelSelectorHBox; | ||
private readonly Dictionary<string, LanguageSelectorItemButton> _selectorStates = new(); | ||
|
||
public event Action<LanguagePrototype>? Selected; | ||
|
||
public LanguageSelectorPopup() | ||
{ | ||
_channelSelectorHBox = new BoxContainer | ||
{ | ||
Orientation = BoxContainer.LayoutOrientation.Horizontal, | ||
SeparationOverride = 1 | ||
}; | ||
|
||
AddChild(_channelSelectorHBox); | ||
} | ||
|
||
public LanguagePrototype? FirstLanguage | ||
{ | ||
get | ||
{ | ||
foreach (var selector in _selectorStates.Values) | ||
{ | ||
if (!selector.IsHidden) | ||
return selector.Language; | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
public void SetLanguages(List<string> languages) | ||
{ | ||
var languageSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<LanguageSystem>(); | ||
_channelSelectorHBox.RemoveAllChildren(); | ||
|
||
foreach (var language in languages) | ||
{ | ||
if (!_selectorStates.TryGetValue(language, out var selector)) | ||
{ | ||
var proto = languageSystem.GetLanguage(language); | ||
if (proto == null) | ||
continue; | ||
|
||
selector = new LanguageSelectorItemButton(proto); | ||
_selectorStates[language] = selector; | ||
selector.OnPressed += OnSelectorPressed; | ||
} | ||
|
||
if (selector.IsHidden) | ||
{ | ||
_channelSelectorHBox.AddChild(selector); | ||
} | ||
} | ||
} | ||
|
||
private void OnSelectorPressed(ButtonEventArgs args) | ||
{ | ||
var button = (LanguageSelectorItemButton) args.Button; | ||
Select(button.Language); | ||
} | ||
|
||
private void Select(LanguagePrototype language) | ||
{ | ||
Selected?.Invoke(language); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps see if you can get anyone experienced in UI involved to make something neat looking? A little slimmer would also probably be better for a utilitarian-menu.
Also this should probably be a FancyWindow