aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormageven <62494521+mageven@users.noreply.github.com>2020-07-21 09:44:42 +0530
committerGitHub <noreply@github.com>2020-07-21 06:14:42 +0200
commit4aa47a66c6d72707ccdf7618bcad2a8e65797e3d (patch)
tree878b44ad4b07f6cefcdbc2362c45d8c851c292f6
parent21dfa4974a6697fff6a476a87a2d31d408f74e0d (diff)
Better TimeZone entry in System Settings (#1254)
* Better timezone labels in System TimeZone Replace with GtkEntry with auto-complete Also removed async task as now loading is fast Address Thog's comments self-nit: Remove string alias Address AcK's comments * Improve parsing * Optimize and fix string matching Address jD's comments * Also, make abbreviations searchable * Optimize EntryCompletion's MatchFunc * nit: Result.IsFailure() * Fix potential crash on opening Settings window w/o FW installed
-rw-r--r--Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs68
-rw-r--r--Ryujinx/Ui/SettingsWindow.cs180
-rw-r--r--Ryujinx/Ui/SettingsWindow.glade10
3 files changed, 190 insertions, 68 deletions
diff --git a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
index 70e1dcb4..e2576425 100644
--- a/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
+++ b/Ryujinx.HLE/HOS/Services/Time/TimeZone/TimeZoneContentManager.cs
@@ -10,6 +10,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Services.Time.Clock;
using Ryujinx.HLE.Utilities;
+using System;
using System.Collections.Generic;
using System.IO;
@@ -117,6 +118,73 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
}
}
+ public IEnumerable<(int Offset, string Location, string Abbr)> ParseTzOffsets()
+ {
+ var tzBinaryContentPath = GetTimeZoneBinaryTitleContentPath();
+
+ if (string.IsNullOrEmpty(tzBinaryContentPath))
+ {
+ return new[] { (0, "UTC", "UTC") };
+ }
+
+ List<(int Offset, string Location, string Abbr)> outList = new List<(int Offset, string Location, string Abbr)>();
+ var now = System.DateTimeOffset.Now.ToUnixTimeSeconds();
+ using (IStorage ncaStorage = new LocalStorage(_virtualFileSystem.SwitchPathToSystemPath(tzBinaryContentPath), FileAccess.Read, FileMode.Open))
+ using (IFileSystem romfs = new Nca(_virtualFileSystem.KeySet, ncaStorage).OpenFileSystem(NcaSectionType.Data, _fsIntegrityCheckLevel))
+ {
+ foreach (string locName in LocationNameCache)
+ {
+ if (locName.StartsWith("Etc"))
+ {
+ continue;
+ }
+
+ if (romfs.OpenFile(out IFile tzif, $"/zoneinfo/{locName}".ToU8Span(), OpenMode.Read).IsFailure())
+ {
+ Logger.PrintError(LogClass.ServiceTime, $"Error opening /zoneinfo/{locName}");
+ continue;
+ }
+
+ using (tzif)
+ {
+ TimeZone.ParseTimeZoneBinary(out TimeZoneRule tzRule, tzif.AsStream());
+
+ TimeTypeInfo ttInfo;
+ if (tzRule.TimeCount > 0) // Find the current transition period
+ {
+ int fin = 0;
+ for (int i = 0; i < tzRule.TimeCount; ++i)
+ {
+ if (tzRule.Ats[i] <= now)
+ {
+ fin = i;
+ }
+ }
+ ttInfo = tzRule.Ttis[tzRule.Types[fin]];
+ }
+ else if (tzRule.TypeCount >= 1) // Otherwise, use the first offset in TTInfo
+ {
+ ttInfo = tzRule.Ttis[0];
+ }
+ else
+ {
+ Logger.PrintError(LogClass.ServiceTime, $"Couldn't find UTC offset for zone {locName}");
+ continue;
+ }
+
+ var abbrStart = tzRule.Chars.AsSpan(ttInfo.AbbreviationListIndex);
+ int abbrEnd = abbrStart.IndexOf('\0');
+
+ outList.Add((ttInfo.GmtOffset, locName, abbrStart.Slice(0, abbrEnd).ToString()));
+ }
+ }
+ }
+
+ outList.Sort();
+
+ return outList;
+ }
+
private bool IsLocationNameValid(string locationName)
{
foreach (string cachedLocationName in LocationNameCache)
diff --git a/Ryujinx/Ui/SettingsWindow.cs b/Ryujinx/Ui/SettingsWindow.cs
index 493260c3..b488fdbb 100644
--- a/Ryujinx/Ui/SettingsWindow.cs
+++ b/Ryujinx/Ui/SettingsWindow.cs
@@ -9,7 +9,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -22,59 +21,62 @@ namespace Ryujinx.Ui
private static ListStore _gameDirsBoxStore;
private static VirtualFileSystem _virtualFileSystem;
+ private TimeZoneContentManager _timeZoneContentManager;
+ private HashSet<string> _validTzRegions;
private long _systemTimeOffset;
#pragma warning disable CS0649, IDE0044
- [GUI] CheckButton _errorLogToggle;
- [GUI] CheckButton _warningLogToggle;
- [GUI] CheckButton _infoLogToggle;
- [GUI] CheckButton _stubLogToggle;
- [GUI] CheckButton _debugLogToggle;
- [GUI] CheckButton _fileLogToggle;
- [GUI] CheckButton _guestLogToggle;
- [GUI] CheckButton _fsAccessLogToggle;
- [GUI] Adjustment _fsLogSpinAdjustment;
- [GUI] CheckButton _dockedModeToggle;
- [GUI] CheckButton _discordToggle;
- [GUI] CheckButton _vSyncToggle;
- [GUI] CheckButton _multiSchedToggle;
- [GUI] CheckButton _ptcToggle;
- [GUI] CheckButton _fsicToggle;
- [GUI] CheckButton _ignoreToggle;
- [GUI] CheckButton _directKeyboardAccess;
- [GUI] ComboBoxText _systemLanguageSelect;
- [GUI] ComboBoxText _systemRegionSelect;
- [GUI] ComboBoxText _systemTimeZoneSelect;
- [GUI] ComboBoxText _audioBackendSelect;
- [GUI] SpinButton _systemTimeYearSpin;
- [GUI] SpinButton _systemTimeMonthSpin;
- [GUI] SpinButton _systemTimeDaySpin;
- [GUI] SpinButton _systemTimeHourSpin;
- [GUI] SpinButton _systemTimeMinuteSpin;
- [GUI] Adjustment _systemTimeYearSpinAdjustment;
- [GUI] Adjustment _systemTimeMonthSpinAdjustment;
- [GUI] Adjustment _systemTimeDaySpinAdjustment;
- [GUI] Adjustment _systemTimeHourSpinAdjustment;
- [GUI] Adjustment _systemTimeMinuteSpinAdjustment;
- [GUI] CheckButton _custThemeToggle;
- [GUI] Entry _custThemePath;
- [GUI] ToggleButton _browseThemePath;
- [GUI] Label _custThemePathLabel;
- [GUI] TreeView _gameDirsBox;
- [GUI] Entry _addGameDirBox;
- [GUI] Entry _graphicsShadersDumpPath;
- [GUI] ComboBoxText _anisotropy;
- [GUI] ComboBoxText _resScaleCombo;
- [GUI] Entry _resScaleText;
- [GUI] ToggleButton _configureController1;
- [GUI] ToggleButton _configureController2;
- [GUI] ToggleButton _configureController3;
- [GUI] ToggleButton _configureController4;
- [GUI] ToggleButton _configureController5;
- [GUI] ToggleButton _configureController6;
- [GUI] ToggleButton _configureController7;
- [GUI] ToggleButton _configureController8;
- [GUI] ToggleButton _configureControllerH;
+ [GUI] CheckButton _errorLogToggle;
+ [GUI] CheckButton _warningLogToggle;
+ [GUI] CheckButton _infoLogToggle;
+ [GUI] CheckButton _stubLogToggle;
+ [GUI] CheckButton _debugLogToggle;
+ [GUI] CheckButton _fileLogToggle;
+ [GUI] CheckButton _guestLogToggle;
+ [GUI] CheckButton _fsAccessLogToggle;
+ [GUI] Adjustment _fsLogSpinAdjustment;
+ [GUI] CheckButton _dockedModeToggle;
+ [GUI] CheckButton _discordToggle;
+ [GUI] CheckButton _vSyncToggle;
+ [GUI] CheckButton _multiSchedToggle;
+ [GUI] CheckButton _ptcToggle;
+ [GUI] CheckButton _fsicToggle;
+ [GUI] CheckButton _ignoreToggle;
+ [GUI] CheckButton _directKeyboardAccess;
+ [GUI] ComboBoxText _systemLanguageSelect;
+ [GUI] ComboBoxText _systemRegionSelect;
+ [GUI] Entry _systemTimeZoneEntry;
+ [GUI] EntryCompletion _systemTimeZoneCompletion;
+ [GUI] ComboBoxText _audioBackendSelect;
+ [GUI] SpinButton _systemTimeYearSpin;
+ [GUI] SpinButton _systemTimeMonthSpin;
+ [GUI] SpinButton _systemTimeDaySpin;
+ [GUI] SpinButton _systemTimeHourSpin;
+ [GUI] SpinButton _systemTimeMinuteSpin;
+ [GUI] Adjustment _systemTimeYearSpinAdjustment;
+ [GUI] Adjustment _systemTimeMonthSpinAdjustment;
+ [GUI] Adjustment _systemTimeDaySpinAdjustment;
+ [GUI] Adjustment _systemTimeHourSpinAdjustment;
+ [GUI] Adjustment _systemTimeMinuteSpinAdjustment;
+ [GUI] CheckButton _custThemeToggle;
+ [GUI] Entry _custThemePath;
+ [GUI] ToggleButton _browseThemePath;
+ [GUI] Label _custThemePathLabel;
+ [GUI] TreeView _gameDirsBox;
+ [GUI] Entry _addGameDirBox;
+ [GUI] Entry _graphicsShadersDumpPath;
+ [GUI] ComboBoxText _anisotropy;
+ [GUI] ComboBoxText _resScaleCombo;
+ [GUI] Entry _resScaleText;
+ [GUI] ToggleButton _configureController1;
+ [GUI] ToggleButton _configureController2;
+ [GUI] ToggleButton _configureController3;
+ [GUI] ToggleButton _configureController4;
+ [GUI] ToggleButton _configureController5;
+ [GUI] ToggleButton _configureController6;
+ [GUI] ToggleButton _configureController7;
+ [GUI] ToggleButton _configureController8;
+ [GUI] ToggleButton _configureControllerH;
#pragma warning restore CS0649, IDE0044
public SettingsWindow(VirtualFileSystem virtualFileSystem, HLE.FileSystem.Content.ContentManager contentManager) : this(new Builder("Ryujinx.Ui.SettingsWindow.glade"), virtualFileSystem, contentManager) { }
@@ -87,6 +89,11 @@ namespace Ryujinx.Ui
_virtualFileSystem = virtualFileSystem;
+ _timeZoneContentManager = new TimeZoneContentManager();
+ _timeZoneContentManager.InitializeInstance(virtualFileSystem, contentManager, LibHac.FsSystem.IntegrityCheckLevel.None);
+
+ _validTzRegions = new HashSet<string>(_timeZoneContentManager.LocationNameCache.Length, StringComparer.Ordinal); // Zone regions are identifiers. Must match exactly.
+
//Bind Events
_configureController1.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player1);
_configureController2.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player2);
@@ -97,6 +104,7 @@ namespace Ryujinx.Ui
_configureController7.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player7);
_configureController8.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Player8);
_configureControllerH.Pressed += (sender, args) => ConfigureController_Pressed(sender, args, PlayerIndex.Handheld);
+ _systemTimeZoneEntry.FocusOutEvent += TimeZoneEntry_FocusOut;
_resScaleCombo.Changed += (sender, args) => _resScaleText.Visible = _resScaleCombo.ActiveId == "-1";
@@ -186,19 +194,6 @@ namespace Ryujinx.Ui
_custThemeToggle.Click();
}
- TimeZoneContentManager timeZoneContentManager = new TimeZoneContentManager();
-
- timeZoneContentManager.InitializeInstance(virtualFileSystem, contentManager, LibHac.FsSystem.IntegrityCheckLevel.None);
-
- List<string> locationNames = timeZoneContentManager.LocationNameCache.ToList();
-
- locationNames.Sort();
-
- foreach (string locationName in locationNames)
- {
- _systemTimeZoneSelect.Append(locationName, locationName);
- }
-
Task.Run(() =>
{
if (SoundIoAudioOut.IsSupported)
@@ -223,9 +218,41 @@ namespace Ryujinx.Ui
});
});
+ // Custom EntryCompletion Columns. If added to glade, need to override more signals
+ ListStore tzList = new ListStore(typeof(string), typeof(string), typeof(string));
+ _systemTimeZoneCompletion.Model = tzList;
+
+ CellRendererText offsetCol = new CellRendererText();
+ CellRendererText abbrevCol = new CellRendererText();
+
+ _systemTimeZoneCompletion.PackStart(offsetCol, false);
+ _systemTimeZoneCompletion.AddAttribute(offsetCol, "text", 0);
+ _systemTimeZoneCompletion.TextColumn = 1; // Regions Column
+ _systemTimeZoneCompletion.PackStart(abbrevCol, false);
+ _systemTimeZoneCompletion.AddAttribute(abbrevCol, "text", 2);
+
+ int maxLocationLength = 0;
+
+ foreach (var (offset, location, abbr) in _timeZoneContentManager.ParseTzOffsets())
+ {
+ var hours = Math.DivRem(offset, 3600, out int seconds);
+ var minutes = Math.Abs(seconds) / 60;
+
+ var abbr2 = (abbr.StartsWith('+') || abbr.StartsWith('-')) ? string.Empty : abbr;
+
+ tzList.AppendValues($"UTC{hours:+0#;-0#;+00}:{minutes:D2} ", location, abbr2);
+ _validTzRegions.Add(location);
+
+ maxLocationLength = Math.Max(maxLocationLength, location.Length);
+ }
+
+ _systemTimeZoneEntry.WidthChars = Math.Max(20, maxLocationLength + 1); // Ensure minimum Entry width
+ _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName();
+
+ _systemTimeZoneCompletion.MatchFunc = TimeZoneMatchFunc;
+
_systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString());
_systemRegionSelect.SetActiveId(ConfigurationState.Instance.System.Region.Value.ToString());
- _systemTimeZoneSelect.SetActiveId(timeZoneContentManager.SanityCheckDeviceLocationName());
_resScaleCombo.SetActiveId(ConfigurationState.Instance.Graphics.ResScale.Value.ToString());
_anisotropy.SetActiveId(ConfigurationState.Instance.Graphics.MaxAnisotropy.Value.ToString());
@@ -290,6 +317,23 @@ namespace Ryujinx.Ui
}
//Events
+ private void TimeZoneEntry_FocusOut(Object sender, FocusOutEventArgs e)
+ {
+ if (!_validTzRegions.Contains(_systemTimeZoneEntry.Text))
+ {
+ _systemTimeZoneEntry.Text = _timeZoneContentManager.SanityCheckDeviceLocationName();
+ }
+ }
+
+ private bool TimeZoneMatchFunc(EntryCompletion compl, string key, TreeIter iter)
+ {
+ key = key.Trim().Replace(' ', '_');
+
+ return ((string)compl.Model.GetValue(iter, 1)).Contains(key, StringComparison.OrdinalIgnoreCase) || // region
+ ((string)compl.Model.GetValue(iter, 2)).StartsWith(key, StringComparison.OrdinalIgnoreCase) || // abbr
+ ((string)compl.Model.GetValue(iter, 0)).Substring(3).StartsWith(key); // offset
+ }
+
private void SystemTimeSpin_ValueChanged(Object sender, EventArgs e)
{
int year = _systemTimeYearSpin.ValueAsInt;
@@ -438,6 +482,11 @@ namespace Ryujinx.Ui
{
resScaleCustom = 1.0f;
}
+
+ if (_validTzRegions.Contains(_systemTimeZoneEntry.Text))
+ {
+ ConfigurationState.Instance.System.TimeZone.Value = _systemTimeZoneEntry.Text;
+ }
ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active;
ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active;
@@ -459,7 +508,6 @@ namespace Ryujinx.Ui
ConfigurationState.Instance.System.Language.Value = Enum.Parse<Language>(_systemLanguageSelect.ActiveId);
ConfigurationState.Instance.System.Region.Value = Enum.Parse<Configuration.System.Region>(_systemRegionSelect.ActiveId);
ConfigurationState.Instance.System.AudioBackend.Value = Enum.Parse<AudioBackend>(_audioBackendSelect.ActiveId);
- ConfigurationState.Instance.System.TimeZone.Value = _systemTimeZoneSelect.ActiveId;
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
diff --git a/Ryujinx/Ui/SettingsWindow.glade b/Ryujinx/Ui/SettingsWindow.glade
index d4877a3a..384fed4d 100644
--- a/Ryujinx/Ui/SettingsWindow.glade
+++ b/Ryujinx/Ui/SettingsWindow.glade
@@ -7,6 +7,11 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkEntryCompletion" id="_systemTimeZoneCompletion">
+ <property name="inline-completion">True</property>
+ <property name="inline-selection">True</property>
+ <property name="minimum-key-length">0</property>
+ </object>
<object class="GtkAdjustment" id="_systemTimeDaySpinAdjustment">
<property name="lower">1</property>
<property name="upper">31</property>
@@ -1224,11 +1229,12 @@
</packing>
</child>
<child>
- <object class="GtkComboBoxText" id="_systemTimeZoneSelect">
+ <object class="GtkEntry" id="_systemTimeZoneEntry">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Change System TimeZone</property>
<property name="margin_left">5</property>
+ <property name="completion">_systemTimeZoneCompletion</property>
</object>
<packing>
<property name="expand">False</property>