forked from Mirror/Ryujinx
GUI: Implement context menu for the game table (#840)
* Add context menu to the game table * Minor bugfix and cleanup * add ability to create directory if it doesn't exist * nit * dont show menu when right-clicking nothing
This commit is contained in:
parent
01a4c80ed5
commit
bd010869a5
5 changed files with 135 additions and 44 deletions
|
@ -43,6 +43,7 @@
|
||||||
<None Remove="Ui\assets\PatreonLogo.png" />
|
<None Remove="Ui\assets\PatreonLogo.png" />
|
||||||
<None Remove="Ui\assets\Icon.png" />
|
<None Remove="Ui\assets\Icon.png" />
|
||||||
<None Remove="Ui\assets\TwitterLogo.png" />
|
<None Remove="Ui\assets\TwitterLogo.png" />
|
||||||
|
<None Remove="Ui\GameTableContextMenu.glade" />
|
||||||
<None Remove="Ui\MainWindow.glade" />
|
<None Remove="Ui\MainWindow.glade" />
|
||||||
<None Remove="Ui\SwitchSettings.glade" />
|
<None Remove="Ui\SwitchSettings.glade" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
<EmbeddedResource Include="Ui\assets\PatreonLogo.png" />
|
<EmbeddedResource Include="Ui\assets\PatreonLogo.png" />
|
||||||
<EmbeddedResource Include="Ui\assets\Icon.png" />
|
<EmbeddedResource Include="Ui\assets\Icon.png" />
|
||||||
<EmbeddedResource Include="Ui\assets\TwitterLogo.png" />
|
<EmbeddedResource Include="Ui\assets\TwitterLogo.png" />
|
||||||
|
<EmbeddedResource Include="Ui\GameTableContextMenu.glade" />
|
||||||
<EmbeddedResource Include="Ui\MainWindow.glade" />
|
<EmbeddedResource Include="Ui\MainWindow.glade" />
|
||||||
<EmbeddedResource Include="Ui\SwitchSettings.glade" />
|
<EmbeddedResource Include="Ui\SwitchSettings.glade" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
75
Ryujinx/Ui/GameTableContextMenu.cs
Normal file
75
Ryujinx/Ui/GameTableContextMenu.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
using Gtk;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
using GUI = Gtk.Builder.ObjectAttribute;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ui
|
||||||
|
{
|
||||||
|
public class GameTableContextMenu : Menu
|
||||||
|
{
|
||||||
|
private static ListStore _gameTableStore;
|
||||||
|
private static TreeIter _rowIter;
|
||||||
|
|
||||||
|
#pragma warning disable CS0649
|
||||||
|
#pragma warning disable IDE0044
|
||||||
|
[GUI] MenuItem _openSaveDir;
|
||||||
|
#pragma warning restore CS0649
|
||||||
|
#pragma warning restore IDE0044
|
||||||
|
|
||||||
|
public GameTableContextMenu(ListStore gameTableStore, TreeIter rowIter) : this(new Builder("Ryujinx.Ui.GameTableContextMenu.glade"), gameTableStore, rowIter) { }
|
||||||
|
|
||||||
|
private GameTableContextMenu(Builder builder, ListStore gameTableStore, TreeIter rowIter) : base(builder.GetObject("_contextMenu").Handle)
|
||||||
|
{
|
||||||
|
builder.Autoconnect(this);
|
||||||
|
|
||||||
|
_openSaveDir.Activated += OpenSaveDir_Clicked;
|
||||||
|
|
||||||
|
_gameTableStore = gameTableStore;
|
||||||
|
_rowIter = rowIter;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Events
|
||||||
|
private void OpenSaveDir_Clicked(object sender, EventArgs args)
|
||||||
|
{
|
||||||
|
string titleName = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[0];
|
||||||
|
string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
|
||||||
|
string saveDir = System.IO.Path.Combine(new VirtualFileSystem().GetNandPath(), "user", "save", "0000000000000000", "00000000000000000000000000000001", titleId, "0");
|
||||||
|
|
||||||
|
if (!Directory.Exists(saveDir))
|
||||||
|
{
|
||||||
|
MessageDialog messageDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Question, ButtonsType.YesNo, null)
|
||||||
|
{
|
||||||
|
Title = "Ryujinx",
|
||||||
|
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
|
||||||
|
Text = $"Could not find save directory for {titleName} [{titleId}]",
|
||||||
|
SecondaryText = "Would you like to create the directory?",
|
||||||
|
WindowPosition = WindowPosition.Center
|
||||||
|
};
|
||||||
|
|
||||||
|
if (messageDialog.Run() == (int)ResponseType.Yes)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(saveDir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageDialog.Dispose();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
messageDialog.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Process.Start(new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
FileName = saveDir,
|
||||||
|
UseShellExecute = true,
|
||||||
|
Verb = "open"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
Ryujinx/Ui/GameTableContextMenu.glade
Normal file
18
Ryujinx/Ui/GameTableContextMenu.glade
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.1 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<object class="GtkMenu" id="_contextMenu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkMenuItem" id="_openSaveDir">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Open the folder where saves for the application is loaded</property>
|
||||||
|
<property name="label" translatable="yes">Open Save Directory</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -38,16 +38,6 @@ namespace Ryujinx.Ui
|
||||||
private static bool _gameLoaded;
|
private static bool _gameLoaded;
|
||||||
private static bool _ending;
|
private static bool _ending;
|
||||||
|
|
||||||
private static TreeViewColumn _favColumn;
|
|
||||||
private static TreeViewColumn _appColumn;
|
|
||||||
private static TreeViewColumn _devColumn;
|
|
||||||
private static TreeViewColumn _versionColumn;
|
|
||||||
private static TreeViewColumn _timePlayedColumn;
|
|
||||||
private static TreeViewColumn _lastPlayedColumn;
|
|
||||||
private static TreeViewColumn _fileExtColumn;
|
|
||||||
private static TreeViewColumn _fileSizeColumn;
|
|
||||||
private static TreeViewColumn _pathColumn;
|
|
||||||
|
|
||||||
private static TreeView _treeView;
|
private static TreeView _treeView;
|
||||||
|
|
||||||
#pragma warning disable CS0649
|
#pragma warning disable CS0649
|
||||||
|
@ -66,6 +56,7 @@ namespace Ryujinx.Ui
|
||||||
[GUI] CheckMenuItem _fileSizeToggle;
|
[GUI] CheckMenuItem _fileSizeToggle;
|
||||||
[GUI] CheckMenuItem _pathToggle;
|
[GUI] CheckMenuItem _pathToggle;
|
||||||
[GUI] TreeView _gameTable;
|
[GUI] TreeView _gameTable;
|
||||||
|
[GUI] TreeSelection _gameTableSelection;
|
||||||
[GUI] Label _progressLabel;
|
[GUI] Label _progressLabel;
|
||||||
[GUI] LevelBar _progressBar;
|
[GUI] LevelBar _progressBar;
|
||||||
#pragma warning restore CS0649
|
#pragma warning restore CS0649
|
||||||
|
@ -81,6 +72,8 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
ApplicationLibrary.ApplicationAdded += Application_Added;
|
ApplicationLibrary.ApplicationAdded += Application_Added;
|
||||||
|
|
||||||
|
_gameTable.ButtonReleaseEvent += Row_Clicked;
|
||||||
|
|
||||||
_renderer = new OglRenderer();
|
_renderer = new OglRenderer();
|
||||||
|
|
||||||
_audioOut = InitializeAudioEngine();
|
_audioOut = InitializeAudioEngine();
|
||||||
|
@ -173,26 +166,16 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
foreach (TreeViewColumn column in _gameTable.Columns)
|
foreach (TreeViewColumn column in _gameTable.Columns)
|
||||||
{
|
{
|
||||||
if (column.Title == "Fav") _favColumn = column;
|
if (column.Title == "Fav" && ConfigurationState.Instance.Ui.GuiColumns.FavColumn) column.SortColumnId = 0;
|
||||||
else if (column.Title == "Application") _appColumn = column;
|
else if (column.Title == "Application" && ConfigurationState.Instance.Ui.GuiColumns.AppColumn) column.SortColumnId = 2;
|
||||||
else if (column.Title == "Developer") _devColumn = column;
|
else if (column.Title == "Developer" && ConfigurationState.Instance.Ui.GuiColumns.DevColumn) column.SortColumnId = 3;
|
||||||
else if (column.Title == "Version") _versionColumn = column;
|
else if (column.Title == "Version" && ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) column.SortColumnId = 4;
|
||||||
else if (column.Title == "Time Played") _timePlayedColumn = column;
|
else if (column.Title == "Time Played" && ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) column.SortColumnId = 5;
|
||||||
else if (column.Title == "Last Played") _lastPlayedColumn = column;
|
else if (column.Title == "Last Played" && ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) column.SortColumnId = 6;
|
||||||
else if (column.Title == "File Ext") _fileExtColumn = column;
|
else if (column.Title == "File Ext" && ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) column.SortColumnId = 7;
|
||||||
else if (column.Title == "File Size") _fileSizeColumn = column;
|
else if (column.Title == "File Size" && ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) column.SortColumnId = 8;
|
||||||
else if (column.Title == "Path") _pathColumn = column;
|
else if (column.Title == "Path" && ConfigurationState.Instance.Ui.GuiColumns.PathColumn) column.SortColumnId = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) _favColumn.SortColumnId = 0;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) _appColumn.SortColumnId = 2;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) _devColumn.SortColumnId = 3;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) _versionColumn.SortColumnId = 4;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) _timePlayedColumn.SortColumnId = 5;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) _lastPlayedColumn.SortColumnId = 6;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) _fileExtColumn.SortColumnId = 7;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) _fileSizeColumn.SortColumnId = 8;
|
|
||||||
if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) _pathColumn.SortColumnId = 9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HLE.Switch InitializeSwitchInstance()
|
private HLE.Switch InitializeSwitchInstance()
|
||||||
|
@ -421,24 +404,24 @@ namespace Ryujinx.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
//Events
|
//Events
|
||||||
private void Application_Added(object sender, ApplicationAddedEventArgs e)
|
private void Application_Added(object sender, ApplicationAddedEventArgs args)
|
||||||
{
|
{
|
||||||
Application.Invoke(delegate
|
Application.Invoke(delegate
|
||||||
{
|
{
|
||||||
_tableStore.AppendValues(
|
_tableStore.AppendValues(
|
||||||
e.AppData.Favorite,
|
args.AppData.Favorite,
|
||||||
new Gdk.Pixbuf(e.AppData.Icon, 75, 75),
|
new Gdk.Pixbuf(args.AppData.Icon, 75, 75),
|
||||||
$"{e.AppData.TitleName}\n{e.AppData.TitleId.ToUpper()}",
|
$"{args.AppData.TitleName}\n{args.AppData.TitleId.ToUpper()}",
|
||||||
e.AppData.Developer,
|
args.AppData.Developer,
|
||||||
e.AppData.Version,
|
args.AppData.Version,
|
||||||
e.AppData.TimePlayed,
|
args.AppData.TimePlayed,
|
||||||
e.AppData.LastPlayed,
|
args.AppData.LastPlayed,
|
||||||
e.AppData.FileExtension,
|
args.AppData.FileExtension,
|
||||||
e.AppData.FileSize,
|
args.AppData.FileSize,
|
||||||
e.AppData.Path);
|
args.AppData.Path);
|
||||||
|
|
||||||
_progressLabel.Text = $"{e.NumAppsLoaded}/{e.NumAppsFound} Games Loaded";
|
_progressLabel.Text = $"{args.NumAppsLoaded}/{args.NumAppsFound} Games Loaded";
|
||||||
_progressBar.Value = (float)e.NumAppsLoaded / e.NumAppsFound;
|
_progressBar.Value = (float)args.NumAppsLoaded / args.NumAppsFound;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,12 +460,25 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private void Row_Activated(object sender, RowActivatedArgs args)
|
private void Row_Activated(object sender, RowActivatedArgs args)
|
||||||
{
|
{
|
||||||
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path.ToString()));
|
_gameTableSelection.GetSelected(out TreeIter treeIter);
|
||||||
string path = (string)_tableStore.GetValue(treeIter, 9);
|
string path = (string)_tableStore.GetValue(treeIter, 9);
|
||||||
|
|
||||||
LoadApplication(path);
|
LoadApplication(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Row_Clicked(object sender, ButtonReleaseEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Event.Button != 3) return;
|
||||||
|
|
||||||
|
_gameTableSelection.GetSelected(out TreeIter treeIter);
|
||||||
|
|
||||||
|
if (treeIter.UserData == IntPtr.Zero) return;
|
||||||
|
|
||||||
|
GameTableContextMenu contextMenu = new GameTableContextMenu(_tableStore, treeIter);
|
||||||
|
contextMenu.ShowAll();
|
||||||
|
contextMenu.PopupAtPointer(null);
|
||||||
|
}
|
||||||
|
|
||||||
private void Load_Application_File(object sender, EventArgs args)
|
private void Load_Application_File(object sender, EventArgs args)
|
||||||
{
|
{
|
||||||
FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
|
FileChooserDialog fileChooser = new FileChooserDialog("Choose the file to open", this, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Open", ResponseType.Accept);
|
||||||
|
|
|
@ -330,7 +330,7 @@
|
||||||
<property name="hover_selection">True</property>
|
<property name="hover_selection">True</property>
|
||||||
<signal name="row-activated" handler="Row_Activated" swapped="no"/>
|
<signal name="row-activated" handler="Row_Activated" swapped="no"/>
|
||||||
<child internal-child="selection">
|
<child internal-child="selection">
|
||||||
<object class="GtkTreeSelection"/>
|
<object class="GtkTreeSelection" id="_gameTableSelection"/>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
|
Loading…
Reference in a new issue