diff --git a/StarterNG/Classes/Settings.cs b/StarterNG/Classes/Settings.cs
index c90d8a2..6a36eaa 100644
--- a/StarterNG/Classes/Settings.cs
+++ b/StarterNG/Classes/Settings.cs
@@ -72,8 +72,6 @@ public sealed class Settings
public int Width = 1280; // width
public int Height = 720; // height
public int BufferScalePercent = 100; // starter.bufferscale → gfx.framebuffer.fidelity
- /// 0 = Reinhard, 1 = ACESFilm (Pascal ChangeHDR).
- public int HdrToneMap; // starter.hdr
public int MaxTextureSize = 4096; // maxtexturesize
public int MaxCabTextureSize = 4096; // maxcabtexturesize
public int TextureFiltering = 8; // anisotropicfiltering (1/2/4/8/16)
@@ -394,15 +392,14 @@ public sealed class Settings
_config.Remove("gfx.framebuffer.fidelity");
}
- /// Copy Reinhard/ACESFilm GLSL into shaders/tonemapping.glsl when present.
+ /// Copy the Reinhard GLSL into shaders/tonemapping.glsl when present.
public void ApplyHdrShader()
{
// Only meaningful for full / legacy / experimental renderers (Pascal).
if (RenderEngine is not (0 or 1 or 5))
return;
- string name = HdrToneMap == 0 ? "Reinhard.glsl" : "ACESFilm.glsl";
- string? src = FindBundled(name);
+ string? src = FindBundled("Reinhard.glsl");
if (src is null) return;
try
@@ -495,7 +492,6 @@ public sealed class Settings
DebugMode = c.GetBool("debugmode", false);
VirtualShunting = c.GetBool("ai.trainman", true);
LogMissingVehicleFiles = c.GetBool("starter.logmissingvehicles", false);
- HdrToneMap = Clamp(c.GetInt("starter.hdr", 0), 0, 1);
// Graphics
RenderEngine = IndexOf(RenderEngines, c.GetString("gfxrenderer", "full"), 0);
@@ -621,7 +617,6 @@ public sealed class Settings
c.SetBool("debugmode", DebugMode);
c.SetBool("ai.trainman", VirtualShunting);
c.SetBool("starter.logmissingvehicles", LogMissingVehicleFiles);
- c.SetInt("starter.hdr", Clamp(HdrToneMap, 0, 1));
// Graphics
c.Set("gfxrenderer", RenderEngines[Clamp(RenderEngine, 0, RenderEngines.Length - 1)]);
diff --git a/StarterNG/MainWindow.axaml.cs b/StarterNG/MainWindow.axaml.cs
index 24e539f..fa6d87f 100644
--- a/StarterNG/MainWindow.axaml.cs
+++ b/StarterNG/MainWindow.axaml.cs
@@ -45,6 +45,7 @@ public partial class MainWindow : Window
TopBar.Padding = new Thickness(0, TitleBarHeight, 0, 0);
PopulateLangCombo();
+ App.Loc.LanguageChanged += OnLanguageChanged;
// Keep Start enabled/caption in sync with selection (Pascal actStartUpdate).
AppState.Instance.Changed += UpdateStartButton;
@@ -79,39 +80,56 @@ public partial class MainWindow : Window
SettingsView.IsVisible = page == "settings";
}
+ // One entry per file in lang/. The entries are language names, which are not
+ // translated, so this runs once - never from OnLanguageChanged, where it
+ // would clear the combo from inside its own SelectionChanged and throw.
private void PopulateLangCombo()
{
LangCombo.Items.Clear();
- int selected = 0;
- var langs = LocalizationService.AvailableLanguages();
- if (langs.Count == 0)
- {
- LangCombo.Items.Add(new ComboBoxItem { Content = "English" });
- LangCombo.SelectedIndex = 0;
- return;
- }
- for (int i = 0; i < langs.Count; i++)
- {
- LangCombo.Items.Add(new ComboBoxItem { Content = langs[i].Name, Tag = langs[i].Code });
- if (string.Equals(langs[i].Name, App.Loc.CurrentLanguage, StringComparison.OrdinalIgnoreCase) ||
- string.Equals(langs[i].Code, App.Loc.CurrentLangCode, StringComparison.OrdinalIgnoreCase))
- selected = i;
- }
- LangCombo.SelectedIndex = selected;
+ foreach (var lang in LocalizationService.AvailableLanguages())
+ LangCombo.Items.Add(new ComboBoxItem { Content = lang.Name, Tag = lang.Code });
+ if (LangCombo.ItemCount == 0)
+ LangCombo.Items.Add(new ComboBoxItem { Content = "English", Tag = "en" });
+
+ SelectActiveLanguage();
+ }
+
+ // Points the combo at the loaded language; a no-op when it already shows it,
+ // which is the case for a pick made here.
+ private void SelectActiveLanguage()
+ {
+ var item = LangCombo.Items.OfType()
+ .FirstOrDefault(it => string.Equals(it.Tag as string, App.Loc.CurrentLangCode,
+ StringComparison.OrdinalIgnoreCase))
+ ?? LangCombo.Items.OfType().FirstOrDefault();
+
+ if (item != null && !ReferenceEquals(LangCombo.SelectedItem, item))
+ LangCombo.SelectedItem = item;
}
private void LangCombo_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
- if (sender is not ComboBox { SelectedItem: ComboBoxItem item }) return;
- if (!item.IsKeyboardFocusWithin) return; // ignore the programmatic initial set
- var lang = item.Tag as string ?? item.Content?.ToString();
- if (!string.IsNullOrEmpty(lang))
- {
- App.ApplyLanguage(lang);
- ScenariosView?.RebuildAfterLanguageChange();
- DepotView?.RebuildAfterLanguageChange();
- UpdateStartButton();
- }
+ if ((LangCombo.SelectedItem as ComboBoxItem)?.Tag is not string code)
+ return;
+
+ // Filling the combo in selects the language that is already loaded, which
+ // lands here as well - comparing against the loaded one is what tells the
+ // two apart, and it keeps the handler idempotent.
+ if (string.Equals(code, App.Loc.CurrentLangCode, StringComparison.OrdinalIgnoreCase))
+ return;
+
+ App.ApplyLanguage(code);
+ }
+
+ // Captions built in code (train stats, panel headers, combo items) are read
+ // from App.Loc once, so they have to be built again. Runs for a pick made
+ // here or in the settings tab, hence hanging off Loc rather off the combo.
+ private void OnLanguageChanged()
+ {
+ SelectActiveLanguage();
+ ScenariosView?.RebuildAfterLanguageChange();
+ DepotView?.RebuildAfterLanguageChange();
+ UpdateStartButton();
}
private void HelpButton_OnClick(object? sender, RoutedEventArgs e)
diff --git a/StarterNG/Services/LocalizationService.cs b/StarterNG/Services/LocalizationService.cs
index 72179ec..da8ec71 100644
--- a/StarterNG/Services/LocalizationService.cs
+++ b/StarterNG/Services/LocalizationService.cs
@@ -29,6 +29,13 @@ public class LocalizationService : INotifyPropertyChanged
public event PropertyChangedEventHandler? PropertyChanged;
+ ///
+ /// Raised after a language file is loaded. XAML bindings refresh themselves
+ /// through ; this is for captions that code
+ /// builds once and has to build again.
+ ///
+ public event Action? LanguageChanged;
+
/// Display name of the active language (e.g. "English", "Polski").
public string CurrentLanguage { get; private set; } = "English";
@@ -113,7 +120,11 @@ public class LocalizationService : INotifyPropertyChanged
CurrentLanguage = "English";
}
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item"));
+ // "Item[]" is the indexer name bindings listen for; the empty name asks
+ // every binding on this object to re-read.
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Item[]"));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
+ LanguageChanged?.Invoke();
return CurrentLanguage;
}
diff --git a/StarterNG/Views/Settings.axaml b/StarterNG/Views/Settings.axaml
index 82f8a45..914c747 100644
--- a/StarterNG/Views/Settings.axaml
+++ b/StarterNG/Views/Settings.axaml
@@ -26,10 +26,9 @@
-
- Polski
- English
-
+
+
@@ -130,13 +129,6 @@
-
-
-
-
-
-
-
@@ -188,6 +180,11 @@
+
+
+
+
-
+
@@ -270,11 +267,6 @@
-
-
-
-
diff --git a/StarterNG/Views/Settings.axaml.cs b/StarterNG/Views/Settings.axaml.cs
index 156b423..9eb884d 100644
--- a/StarterNG/Views/Settings.axaml.cs
+++ b/StarterNG/Views/Settings.axaml.cs
@@ -12,6 +12,7 @@ using Avalonia.Layout;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Media;
using StarterNG.Classes;
+using StarterNG.Services;
// Disambiguate from Avalonia.Input.KeyBinding (a command-input binding) imported above.
using KeyBinding = StarterNG.Classes.KeyBinding;
@@ -34,11 +35,10 @@ public partial class Settings : UserControl
shaderResolutionSlider_OnValueChanged(null, null);
};
- ChangeLanguageCb.SelectedIndex = App.Loc.CurrentLanguage switch
- {
- "Polski" => 0,
- _ => 1
- };
+ FillLanguageCombo();
+ // The other picker is in the main window's top bar; both follow whatever
+ // language ends up loaded.
+ App.Loc.LanguageChanged += SelectActiveLanguage;
FeedbackCb.SelectionChanged += FeedbackCb_OnSelectionChanged;
FpsLimitEnableCb.IsCheckedChanged += (_, _) => FpsLimitSlider.IsEnabled = IsChecked(FpsLimitEnableCb);
@@ -143,7 +143,7 @@ public partial class Settings : UserControl
PopulateExeCombo();
// General
- ChangeLanguageCb.SelectedIndex = s.Language == "Polski" ? 0 : 1;
+ SelectActiveLanguage();
FullscreenCb.IsChecked = s.Fullscreen;
PauseInactiveCb.IsChecked = s.PauseWhenInactive;
PauseStartCb.IsChecked = s.PauseOnStart;
@@ -177,7 +177,6 @@ public partial class Settings : UserControl
// Graphics
RenderEngineCb.SelectedIndex = s.RenderEngine;
- HdrToneMapCb.SelectedIndex = Clamp(s.HdrToneMap, 0, 1);
SelectResolution(s.Width, s.Height);
bufferScale.Value = s.BufferScalePercent;
textureResolutionSlider.Value = Log2(s.MaxTextureSize, 12);
@@ -264,7 +263,10 @@ public partial class Settings : UserControl
var s = StarterNG.Classes.Settings.Instance;
// General
- s.Language = ChangeLanguageCb.SelectedIndex == 0 ? "Polski" : "English";
+ // Keep the loaded language rather than writing a wrong one over it when
+ // the combo has no valid pick.
+ s.Language = (ChangeLanguageCb.SelectedItem as ComboBoxItem)?.Content?.ToString()
+ ?? App.Loc.CurrentLanguage;
s.Fullscreen = IsChecked(FullscreenCb);
s.PauseWhenInactive = IsChecked(PauseInactiveCb);
s.PauseOnStart = IsChecked(PauseStartCb);
@@ -297,7 +299,6 @@ public partial class Settings : UserControl
// Graphics
s.RenderEngine = Math.Max(0, RenderEngineCb.SelectedIndex);
- s.HdrToneMap = Clamp(HdrToneMapCb.SelectedIndex, 0, 1);
ReadResolution(s);
s.BufferScalePercent = (int)bufferScale.Value;
s.MaxTextureSize = 1 << (int)textureResolutionSlider.Value;
@@ -454,14 +455,39 @@ public partial class Settings : UserControl
shaderResolution.Text = $"{resolution} px";
}
+ // One entry per file in the lang/ folder, so every translation is reachable
+ // (the list used to be a hard-coded Polski / English pair).
+ private void FillLanguageCombo()
+ {
+ ChangeLanguageCb.Items.Clear();
+ foreach (var lang in LocalizationService.AvailableLanguages())
+ ChangeLanguageCb.Items.Add(new ComboBoxItem { Content = lang.Name, Tag = lang.Code });
+ if (ChangeLanguageCb.ItemCount == 0)
+ ChangeLanguageCb.Items.Add(new ComboBoxItem { Content = "English", Tag = "en" });
+ SelectActiveLanguage();
+ }
+
+ // Points the combo at the language currently loaded. The selection change
+ // lands in the handler below, which sees it is already loaded and stops.
+ private void SelectActiveLanguage()
+ {
+ var item = ChangeLanguageCb.Items.OfType()
+ .FirstOrDefault(it => string.Equals(it.Tag as string, App.Loc.CurrentLangCode,
+ StringComparison.OrdinalIgnoreCase))
+ ?? ChangeLanguageCb.Items.OfType().FirstOrDefault();
+
+ if (item != null && !ReferenceEquals(ChangeLanguageCb.SelectedItem, item))
+ ChangeLanguageCb.SelectedItem = item;
+ }
+
private void LanguageComboBox_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
- if (sender is not ComboBox { SelectedItem: ComboBoxItem item }) return;
- if (!item.IsKeyboardFocusWithin) return; // ignore programmatic (ApplyToUi) changes
- var lang = item.Content?.ToString();
- if (string.IsNullOrEmpty(lang)) return;
+ if ((ChangeLanguageCb.SelectedItem as ComboBoxItem)?.Tag is not string code)
+ return;
+ if (string.Equals(code, App.Loc.CurrentLangCode, StringComparison.OrdinalIgnoreCase))
+ return;
- App.ApplyLanguage(lang);
+ App.ApplyLanguage(code);
}
private void FeedbackCb_OnSelectionChanged(object? sender, SelectionChangedEventArgs e) =>
diff --git a/StarterNG/startercfg/lang/cz.xml b/StarterNG/startercfg/lang/cz.xml
index 23191c3..8cc2e7a 100644
--- a/StarterNG/startercfg/lang/cz.xml
+++ b/StarterNG/startercfg/lang/cz.xml
@@ -223,7 +223,6 @@
AnoNeInformace
- Mapování tónů HDRNastaveníSoubor eu07.ini byl změněn mimo starter. Načíst jej znovu?Přidat celou kategorii
diff --git a/StarterNG/startercfg/lang/en.xml b/StarterNG/startercfg/lang/en.xml
index 747eeea..fc8ec32 100644
--- a/StarterNG/startercfg/lang/en.xml
+++ b/StarterNG/startercfg/lang/en.xml
@@ -223,7 +223,6 @@
YesNoInfo
- HDR tone mappingSettingseu07.ini was changed outside the starter. Reload it?Add whole category
diff --git a/StarterNG/startercfg/lang/hu.xml b/StarterNG/startercfg/lang/hu.xml
index 9149d40..0ff8c56 100644
--- a/StarterNG/startercfg/lang/hu.xml
+++ b/StarterNG/startercfg/lang/hu.xml
@@ -223,7 +223,6 @@
IgenNemInformáció
- HDR tónusleképezésBeállításokAz eu07.ini fájl a starteren kívül módosult. Újratölti?Teljes kategória hozzáadása
diff --git a/StarterNG/startercfg/lang/pl.xml b/StarterNG/startercfg/lang/pl.xml
index e2215eb..3bc69cc 100644
--- a/StarterNG/startercfg/lang/pl.xml
+++ b/StarterNG/startercfg/lang/pl.xml
@@ -223,7 +223,6 @@
TakNieInformacje
- Tone mapping HDRUstawieniaPlik eu07.ini został zmieniony poza starterem. Wczytać ponownie?Dodaj całą kategorię
diff --git a/StarterNG/startercfg/lang/ru.xml b/StarterNG/startercfg/lang/ru.xml
index a226348..8fff66c 100644
--- a/StarterNG/startercfg/lang/ru.xml
+++ b/StarterNG/startercfg/lang/ru.xml
@@ -223,7 +223,6 @@
ДаНетИнформация
- Тональная компрессия HDRНастройкиФайл eu07.ini изменён вне стартера. Загрузить заново?Добавить всю категорию