Remember GUI column sort and separate hotkey settings from emulated input settings (#1223)

* Separate hotkey settings from emulated input settings

* Remember gui column sort

* nit

* fix schema

* nit

* Remove unused SaveDataPath to speed up game list loading

* Reset the vertical scrollbar to the top when titles finish loading
This commit is contained in:
Xpl0itR 2020-06-26 11:30:16 +01:00 committed by GitHub
parent 9a49f8aec9
commit 68a6960617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 805 additions and 518 deletions

View File

@ -13,7 +13,7 @@ namespace Ryujinx.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 8; public const int CurrentVersion = 9;
public int Version { get; set; } public int Version { get; set; }
@ -137,6 +137,11 @@ namespace Ryujinx.Configuration
/// </summary> /// </summary>
public GuiColumns GuiColumns { get; set; } public GuiColumns GuiColumns { get; set; }
/// <summary>
/// Used to configure column sort settings in the GUI
/// </summary>
public ColumnSort ColumnSort { get; set; }
/// <summary> /// <summary>
/// A list of directories containing games to be used to load games into the games list /// A list of directories containing games to be used to load games into the games list
/// </summary> /// </summary>
@ -157,6 +162,11 @@ namespace Ryujinx.Configuration
/// </summary> /// </summary>
public bool EnableKeyboard { get; set; } public bool EnableKeyboard { get; set; }
/// <summary>
/// Hotkey Keyboard Bindings
/// </summary>
public KeyboardHotkeys Hotkeys { get; set; }
/// <summary> /// <summary>
/// Keyboard control bindings /// Keyboard control bindings
/// </summary> /// </summary>

View File

@ -44,11 +44,28 @@ namespace Ryujinx.Configuration
} }
} }
public class ColumnSortSettings
{
public ReactiveObject<int> SortColumnId { get; private set; }
public ReactiveObject<bool> SortAscending { get; private set; }
public ColumnSortSettings()
{
SortColumnId = new ReactiveObject<int>();
SortAscending = new ReactiveObject<bool>();
}
}
/// <summary> /// <summary>
/// Used to toggle columns in the GUI /// Used to toggle columns in the GUI
/// </summary> /// </summary>
public Columns GuiColumns { get; private set; } public Columns GuiColumns { get; private set; }
/// <summary>
/// Used to configure column sort settings in the GUI
/// </summary>
public ColumnSortSettings ColumnSort { get; private set; }
/// <summary> /// <summary>
/// A list of directories containing games to be used to load games into the games list /// A list of directories containing games to be used to load games into the games list
/// </summary> /// </summary>
@ -67,6 +84,7 @@ namespace Ryujinx.Configuration
public UiSection() public UiSection()
{ {
GuiColumns = new Columns(); GuiColumns = new Columns();
ColumnSort = new ColumnSortSettings();
GameDirs = new ReactiveObject<List<string>>(); GameDirs = new ReactiveObject<List<string>>();
EnableCustomTheme = new ReactiveObject<bool>(); EnableCustomTheme = new ReactiveObject<bool>();
CustomThemePath = new ReactiveObject<string>(); CustomThemePath = new ReactiveObject<string>();
@ -217,6 +235,11 @@ namespace Ryujinx.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> EnableKeyboard { get; private set; } public ReactiveObject<bool> EnableKeyboard { get; private set; }
/// <summary>
/// Hotkey Keyboard Bindings
/// </summary>
public ReactiveObject<KeyboardHotkeys> Hotkeys { get; private set; }
/// <summary> /// <summary>
/// Input device configuration. /// Input device configuration.
/// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed. /// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
@ -227,6 +250,7 @@ namespace Ryujinx.Configuration
public HidSection() public HidSection()
{ {
EnableKeyboard = new ReactiveObject<bool>(); EnableKeyboard = new ReactiveObject<bool>();
Hotkeys = new ReactiveObject<KeyboardHotkeys>();
InputConfig = new ReactiveObject<List<InputConfig>>(); InputConfig = new ReactiveObject<List<InputConfig>>();
} }
} }
@ -347,7 +371,7 @@ namespace Ryujinx.Configuration
EnableFsIntegrityChecks = System.EnableFsIntegrityChecks, EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
FsGlobalAccessLogMode = System.FsGlobalAccessLogMode, FsGlobalAccessLogMode = System.FsGlobalAccessLogMode,
IgnoreMissingServices = System.IgnoreMissingServices, IgnoreMissingServices = System.IgnoreMissingServices,
GuiColumns = new GuiColumns() GuiColumns = new GuiColumns
{ {
FavColumn = Ui.GuiColumns.FavColumn, FavColumn = Ui.GuiColumns.FavColumn,
IconColumn = Ui.GuiColumns.IconColumn, IconColumn = Ui.GuiColumns.IconColumn,
@ -360,10 +384,16 @@ namespace Ryujinx.Configuration
FileSizeColumn = Ui.GuiColumns.FileSizeColumn, FileSizeColumn = Ui.GuiColumns.FileSizeColumn,
PathColumn = Ui.GuiColumns.PathColumn, PathColumn = Ui.GuiColumns.PathColumn,
}, },
ColumnSort = new ColumnSort
{
SortColumnId = Ui.ColumnSort.SortColumnId,
SortAscending = Ui.ColumnSort.SortAscending
},
GameDirs = Ui.GameDirs, GameDirs = Ui.GameDirs,
EnableCustomTheme = Ui.EnableCustomTheme, EnableCustomTheme = Ui.EnableCustomTheme,
CustomThemePath = Ui.CustomThemePath, CustomThemePath = Ui.CustomThemePath,
EnableKeyboard = Hid.EnableKeyboard, EnableKeyboard = Hid.EnableKeyboard,
Hotkeys = Hid.Hotkeys,
KeyboardConfig = keyboardConfigList, KeyboardConfig = keyboardConfigList,
ControllerConfig = controllerConfigList ControllerConfig = controllerConfigList
}; };
@ -406,11 +436,18 @@ namespace Ryujinx.Configuration
Ui.GuiColumns.FileExtColumn.Value = true; Ui.GuiColumns.FileExtColumn.Value = true;
Ui.GuiColumns.FileSizeColumn.Value = true; Ui.GuiColumns.FileSizeColumn.Value = true;
Ui.GuiColumns.PathColumn.Value = true; Ui.GuiColumns.PathColumn.Value = true;
Ui.ColumnSort.SortColumnId.Value = 0;
Ui.ColumnSort.SortAscending.Value = false;
Ui.GameDirs.Value = new List<string>(); Ui.GameDirs.Value = new List<string>();
Ui.EnableCustomTheme.Value = false; Ui.EnableCustomTheme.Value = false;
Ui.CustomThemePath.Value = ""; Ui.CustomThemePath.Value = "";
Hid.EnableKeyboard.Value = false; Hid.EnableKeyboard.Value = false;
Hid.Hotkeys.Value = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
};
Hid.InputConfig.Value = new List<InputConfig> Hid.InputConfig.Value = new List<InputConfig>
{ {
new KeyboardConfig new KeyboardConfig
@ -451,10 +488,6 @@ namespace Ryujinx.Configuration
ButtonZr = Key.O, ButtonZr = Key.O,
ButtonSl = Key.PageUp, ButtonSl = Key.PageUp,
ButtonSr = Key.PageDown ButtonSr = Key.PageDown
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
} }
} }
}; };
@ -553,10 +586,6 @@ namespace Ryujinx.Configuration
ButtonZr = Key.O, ButtonZr = Key.O,
ButtonSl = Key.Unbound, ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound ButtonSr = Key.Unbound
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
} }
} }
}; };
@ -587,6 +616,24 @@ namespace Ryujinx.Configuration
configurationFileUpdated = true; configurationFileUpdated = true;
} }
if (configurationFileFormat.Version < 9)
{
Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");
configurationFileFormat.ColumnSort = new ColumnSort
{
SortColumnId = 0,
SortAscending = false
};
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
};
configurationFileUpdated = true;
}
List<InputConfig> inputConfig = new List<InputConfig>(); List<InputConfig> inputConfig = new List<InputConfig>();
foreach (ControllerConfig controllerConfig in configurationFileFormat.ControllerConfig) foreach (ControllerConfig controllerConfig in configurationFileFormat.ControllerConfig)
{ {
@ -631,10 +678,13 @@ namespace Ryujinx.Configuration
Ui.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; Ui.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn;
Ui.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; Ui.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn;
Ui.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; Ui.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn;
Ui.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId;
Ui.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending;
Ui.GameDirs.Value = configurationFileFormat.GameDirs; Ui.GameDirs.Value = configurationFileFormat.GameDirs;
Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme;
Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath; Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath;
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard; Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
Hid.InputConfig.Value = inputConfig; Hid.InputConfig.Value = inputConfig;
if (configurationFileUpdated) if (configurationFileUpdated)

View File

@ -14,10 +14,5 @@ namespace Ryujinx.Common.Configuration.Hid
/// Right JoyCon Keyboard Bindings /// Right JoyCon Keyboard Bindings
/// </summary> /// </summary>
public NpadKeyboardRight RightJoycon { get; set; } public NpadKeyboardRight RightJoycon { get; set; }
/// <summary>
/// Hotkey Keyboard Bindings
/// </summary>
public KeyboardHotkeys Hotkeys { get; set; }
} }
} }

View File

@ -0,0 +1,8 @@
namespace Ryujinx.Configuration.Ui
{
public struct ColumnSort
{
public int SortColumnId { get; set; }
public bool SortAscending { get; set; }
}
}

View File

@ -1,5 +1,5 @@
{ {
"version": 8, "version": 9,
"max_anisotropy": -1, "max_anisotropy": -1,
"graphics_shaders_dump_path": "", "graphics_shaders_dump_path": "",
"logging_enable_debug": false, "logging_enable_debug": false,
@ -35,10 +35,17 @@
"file_size_column": true, "file_size_column": true,
"path_column": true "path_column": true
}, },
"column_sort": {
"sort_column_id": 0,
"sort_ascending": false
},
"game_dirs": [], "game_dirs": [],
"enable_custom_theme": false, "enable_custom_theme": false,
"custom_theme_path": "", "custom_theme_path": "",
"enable_keyboard": false, "enable_keyboard": false,
"hotkeys": {
"toggle_vsync": "Tab"
},
"keyboard_config": [ "keyboard_config": [
{ {
"index": 0, "index": 0,
@ -75,9 +82,6 @@
"button_zr": "O", "button_zr": "O",
"button_sl": "Unbound", "button_sl": "Unbound",
"button_sr": "Unbound" "button_sr": "Unbound"
},
"hotkeys": {
"toggle_vsync": "Tab"
} }
} }
], ],

View File

@ -17,7 +17,6 @@ namespace Ryujinx.Ui
public string FileExtension { get; set; } public string FileExtension { get; set; }
public string FileSize { get; set; } public string FileSize { get; set; }
public string Path { get; set; } public string Path { get; set; }
public string SaveDataPath { get; set; }
public BlitStruct<ApplicationControlProperty> ControlHolder { get; set; } public BlitStruct<ApplicationControlProperty> ControlHolder { get; set; }
} }
} }

View File

@ -131,7 +131,6 @@ namespace Ryujinx.Ui
string titleId = "0000000000000000"; string titleId = "0000000000000000";
string developer = "Unknown"; string developer = "Unknown";
string version = "0"; string version = "0";
string saveDataPath = null;
byte[] applicationIcon = null; byte[] applicationIcon = null;
BlitStruct<ApplicationControlProperty> controlHolder = new BlitStruct<ApplicationControlProperty>(1); BlitStruct<ApplicationControlProperty> controlHolder = new BlitStruct<ApplicationControlProperty>(1);
@ -389,20 +388,6 @@ namespace Ryujinx.Ui
ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId); ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);
if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNum))
{
SaveDataFilter filter = new SaveDataFilter();
filter.SetUserId(new UserId(1, 0));
filter.SetProgramId(new TitleId(titleIdNum));
Result result = virtualFileSystem.FsClient.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter);
if (result.IsSuccess())
{
saveDataPath = Path.Combine(virtualFileSystem.GetNandPath(), "user", "save", saveDataInfo.SaveDataId.ToString("x16"));
}
}
ApplicationData data = new ApplicationData ApplicationData data = new ApplicationData
{ {
Favorite = appMetadata.Favorite, Favorite = appMetadata.Favorite,
@ -416,7 +401,6 @@ namespace Ryujinx.Ui
FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1), FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB", FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
Path = applicationPath, Path = applicationPath,
SaveDataPath = saveDataPath,
ControlHolder = controlHolder ControlHolder = controlHolder
}; };

View File

@ -419,10 +419,6 @@ namespace Ryujinx.Ui
ButtonZr = rButtonZr, ButtonZr = rButtonZr,
ButtonSl = rButtonSl, ButtonSl = rButtonSl,
ButtonSr = rButtonSr ButtonSr = rButtonSr
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab //TODO: Make this an option in the GUI
} }
}; };
} }
@ -754,10 +750,6 @@ namespace Ryujinx.Ui
ButtonZr = Key.O, ButtonZr = Key.O,
ButtonSl = Key.Unbound, ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound ButtonSr = Key.Unbound
},
Hotkeys = new KeyboardHotkeys
{
ToggleVsync = Key.Tab
} }
}; };
} }

View File

@ -449,17 +449,6 @@ namespace Ryujinx.Ui
{ {
_device.Hid.Keyboard.Update(hidKeyboard.Value); _device.Hid.Keyboard.Update(hidKeyboard.Value);
} }
// Toggle vsync
HotkeyButtons currentHotkeyButtons = keyboardController.GetHotkeyButtons();
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
{
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
}
_prevHotkeyButtons = currentHotkeyButtons;
} }
} }
else if (inputConfig is Common.Configuration.Hid.ControllerConfig controllerConfig) else if (inputConfig is Common.Configuration.Hid.ControllerConfig controllerConfig)
@ -498,6 +487,17 @@ namespace Ryujinx.Ui
_device.Hid.Npads.SetGamepadsInput(gamepadInputs.ToArray()); _device.Hid.Npads.SetGamepadsInput(gamepadInputs.ToArray());
// Hotkeys
HotkeyButtons currentHotkeyButtons = KeyboardController.GetHotkeyButtons(OpenTK.Input.Keyboard.GetState());
if (currentHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync) &&
!_prevHotkeyButtons.HasFlag(HotkeyButtons.ToggleVSync))
{
_device.EnableDeviceVsync = !_device.EnableDeviceVsync;
}
_prevHotkeyButtons = currentHotkeyButtons;
//Touchscreen //Touchscreen
bool hasTouch = false; bool hasTouch = false;

View File

@ -1,6 +1,7 @@
using System; using System;
using OpenTK.Input; using OpenTK.Input;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Configuration;
using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.HOS.Services.Hid;
namespace Ryujinx.Ui namespace Ryujinx.Ui
@ -91,20 +92,21 @@ namespace Ryujinx.Ui
return (dx, dy); return (dx, dy);
} }
public HotkeyButtons GetHotkeyButtons() public static HotkeyButtons GetHotkeyButtons(KeyboardState keyboard)
{ {
KeyboardState keyboard = GetKeyboardState(_config.Index);
HotkeyButtons buttons = 0; HotkeyButtons buttons = 0;
if (keyboard[(Key)_config.Hotkeys.ToggleVsync]) buttons |= HotkeyButtons.ToggleVSync; if (keyboard[(Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ToggleVsync])
{
buttons |= HotkeyButtons.ToggleVSync;
}
return buttons; return buttons;
} }
class KeyMappingEntry class KeyMappingEntry
{ {
public Key TargetKey; public Key TargetKey;
public byte Target; public byte Target;
} }

View File

@ -167,7 +167,11 @@ namespace Ryujinx.Ui
_tableStore.SetSortFunc(5, TimePlayedSort); _tableStore.SetSortFunc(5, TimePlayedSort);
_tableStore.SetSortFunc(6, LastPlayedSort); _tableStore.SetSortFunc(6, LastPlayedSort);
_tableStore.SetSortFunc(8, FileSizeSort); _tableStore.SetSortFunc(8, FileSizeSort);
_tableStore.SetSortColumnId(0, SortType.Descending);
int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId;
bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending;
_tableStore.SetSortColumnId(columnId, ascending ? SortType.Ascending : SortType.Descending);
_gameTable.EnableSearch = true; _gameTable.EnableSearch = true;
_gameTable.SearchColumn = 2; _gameTable.SearchColumn = 2;
@ -254,15 +258,45 @@ namespace Ryujinx.Ui
foreach (TreeViewColumn column in _gameTable.Columns) foreach (TreeViewColumn column in _gameTable.Columns)
{ {
if (column.Title == "Fav" && ConfigurationState.Instance.Ui.GuiColumns.FavColumn) column.SortColumnId = 0; switch (column.Title)
else if (column.Title == "Application" && ConfigurationState.Instance.Ui.GuiColumns.AppColumn) column.SortColumnId = 2; {
else if (column.Title == "Developer" && ConfigurationState.Instance.Ui.GuiColumns.DevColumn) column.SortColumnId = 3; case "Fav":
else if (column.Title == "Version" && ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) column.SortColumnId = 4; column.SortColumnId = 0;
else if (column.Title == "Time Played" && ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) column.SortColumnId = 5; column.Clicked += Column_Clicked;
else if (column.Title == "Last Played" && ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) column.SortColumnId = 6; break;
else if (column.Title == "File Ext" && ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) column.SortColumnId = 7; case "Application":
else if (column.Title == "File Size" && ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) column.SortColumnId = 8; column.SortColumnId = 2;
else if (column.Title == "Path" && ConfigurationState.Instance.Ui.GuiColumns.PathColumn) column.SortColumnId = 9; column.Clicked += Column_Clicked;
break;
case "Developer":
column.SortColumnId = 3;
column.Clicked += Column_Clicked;
break;
case "Version":
column.SortColumnId = 4;
column.Clicked += Column_Clicked;
break;
case "Time Played":
column.SortColumnId = 5;
column.Clicked += Column_Clicked;
break;
case "Last Played":
column.SortColumnId = 6;
column.Clicked += Column_Clicked;
break;
case "File Ext":
column.SortColumnId = 7;
column.Clicked += Column_Clicked;
break;
case "File Size":
column.SortColumnId = 8;
column.Clicked += Column_Clicked;
break;
case "Path":
column.SortColumnId = 9;
column.Clicked += Column_Clicked;
break;
}
} }
} }
@ -666,6 +700,11 @@ namespace Ryujinx.Ui
} }
_progressBar.Value = barValue; _progressBar.Value = barValue;
if (args.NumAppsLoaded == args.NumAppsFound) // Reset the vertical scrollbar to the top when titles finish loading
{
_gameTableWindow.Vadjustment.Value = 0;
}
}); });
} }
@ -707,6 +746,16 @@ namespace Ryujinx.Ui
}); });
} }
private void Column_Clicked(object sender, EventArgs args)
{
TreeViewColumn column = (TreeViewColumn)sender;
ConfigurationState.Instance.Ui.ColumnSort.SortColumnId.Value = column.SortColumnId;
ConfigurationState.Instance.Ui.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending;
SaveConfig();
}
private void Row_Activated(object sender, RowActivatedArgs args) private void Row_Activated(object sender, RowActivatedArgs args)
{ {
_gameTableSelection.GetSelected(out TreeIter treeIter); _gameTableSelection.GetSelected(out TreeIter treeIter);

File diff suppressed because it is too large Load Diff