e3b36db71c
* hle: Some cleanup This PR cleaned up a bit the HLE folder and the VirtualFileSystem one, since we use LibHac, we can use some class of it directly instead of duplicate things. The "Content" of VFS folder is removed since it should be handled in the NCM service directly. A larger cleanup should be done later since there is still be duplicated code here and there. * Fix Headless.SDL2 * Addresses gdkchan feedback
330 lines
11 KiB
C#
330 lines
11 KiB
C#
using Gtk;
|
|
using Ryujinx.HLE.FileSystem;
|
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
using Ryujinx.Ui.Widgets;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
using Image = SixLabors.ImageSharp.Image;
|
|
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
|
|
|
namespace Ryujinx.Ui.Windows
|
|
{
|
|
public partial class UserProfilesManagerWindow : Window
|
|
{
|
|
private const uint MaxProfileNameLength = 0x20;
|
|
|
|
private readonly AccountManager _accountManager;
|
|
private readonly ContentManager _contentManager;
|
|
|
|
private byte[] _bufferImageProfile;
|
|
private string _tempNewProfileName;
|
|
|
|
private Gdk.RGBA _selectedColor;
|
|
|
|
private ManualResetEvent _avatarsPreloadingEvent = new ManualResetEvent(false);
|
|
|
|
public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles")
|
|
{
|
|
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.Resources.Logo_Ryujinx.png");
|
|
|
|
InitializeComponent();
|
|
|
|
_selectedColor.Red = 0.212;
|
|
_selectedColor.Green = 0.843;
|
|
_selectedColor.Blue = 0.718;
|
|
_selectedColor.Alpha = 1;
|
|
|
|
_accountManager = accountManager;
|
|
_contentManager = contentManager;
|
|
|
|
CellRendererToggle userSelectedToggle = new CellRendererToggle();
|
|
userSelectedToggle.Toggled += UserSelectedToggle_Toggled;
|
|
|
|
// NOTE: Uncomment following line when multiple selection of user profiles is supported.
|
|
//_usersTreeView.AppendColumn("Selected", userSelectedToggle, "active", 0);
|
|
_usersTreeView.AppendColumn("User Icon", new CellRendererPixbuf(), "pixbuf", 1);
|
|
_usersTreeView.AppendColumn("User Info", new CellRendererText(), "text", 2, "background-rgba", 3);
|
|
|
|
_tableStore.SetSortColumnId(0, SortType.Descending);
|
|
|
|
RefreshList();
|
|
|
|
if (_contentManager.GetCurrentFirmwareVersion() != null)
|
|
{
|
|
Task.Run(() =>
|
|
{
|
|
AvatarWindow.PreloadAvatars(contentManager, virtualFileSystem);
|
|
_avatarsPreloadingEvent.Set();
|
|
});
|
|
}
|
|
}
|
|
|
|
public void RefreshList()
|
|
{
|
|
_tableStore.Clear();
|
|
|
|
foreach (UserProfile userProfile in _accountManager.GetAllUsers())
|
|
{
|
|
_tableStore.AppendValues(userProfile.AccountState == AccountState.Open, new Gdk.Pixbuf(userProfile.Image, 96, 96), $"{userProfile.Name}\n{userProfile.UserId}", Gdk.RGBA.Zero);
|
|
|
|
if (userProfile.AccountState == AccountState.Open)
|
|
{
|
|
_selectedUserImage.Pixbuf = new Gdk.Pixbuf(userProfile.Image, 96, 96);
|
|
_selectedUserIdLabel.Text = userProfile.UserId.ToString();
|
|
_selectedUserNameEntry.Text = userProfile.Name;
|
|
|
|
_deleteButton.Sensitive = userProfile.UserId != AccountManager.DefaultUserId;
|
|
|
|
_usersTreeView.Model.GetIterFirst(out TreeIter firstIter);
|
|
_tableStore.SetValue(firstIter, 3, _selectedColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Events
|
|
//
|
|
|
|
private void UsersTreeView_Activated(object o, RowActivatedArgs args)
|
|
{
|
|
SelectUserTreeView();
|
|
}
|
|
|
|
private void UserSelectedToggle_Toggled(object o, ToggledArgs args)
|
|
{
|
|
SelectUserTreeView();
|
|
}
|
|
|
|
private void SelectUserTreeView()
|
|
{
|
|
// Get selected item informations.
|
|
_usersTreeView.Selection.GetSelected(out TreeIter selectedIter);
|
|
|
|
Gdk.Pixbuf userPicture = (Gdk.Pixbuf)_tableStore.GetValue(selectedIter, 1);
|
|
|
|
string userName = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[0];
|
|
string userId = _tableStore.GetValue(selectedIter, 2).ToString().Split("\n")[1];
|
|
|
|
// Unselect the first user.
|
|
_usersTreeView.Model.GetIterFirst(out TreeIter firstIter);
|
|
_tableStore.SetValue(firstIter, 0, false);
|
|
_tableStore.SetValue(firstIter, 3, Gdk.RGBA.Zero);
|
|
|
|
// Set new informations.
|
|
_tableStore.SetValue(selectedIter, 0, true);
|
|
|
|
_selectedUserImage.Pixbuf = userPicture;
|
|
_selectedUserNameEntry.Text = userName;
|
|
_selectedUserIdLabel.Text = userId;
|
|
_saveProfileNameButton.Sensitive = false;
|
|
|
|
// Open the selected one.
|
|
_accountManager.OpenUser(new UserId(userId));
|
|
|
|
_deleteButton.Sensitive = userId != AccountManager.DefaultUserId.ToString();
|
|
|
|
_tableStore.SetValue(selectedIter, 3, _selectedColor);
|
|
}
|
|
|
|
private void SelectedUserNameEntry_KeyReleaseEvent(object o, KeyReleaseEventArgs args)
|
|
{
|
|
if (_saveProfileNameButton.Sensitive == false)
|
|
{
|
|
_saveProfileNameButton.Sensitive = true;
|
|
}
|
|
}
|
|
|
|
private void AddButton_Pressed(object sender, EventArgs e)
|
|
{
|
|
_tempNewProfileName = GtkDialog.CreateInputDialog(this, "Choose the Profile Name", "Please Enter a Profile Name", MaxProfileNameLength);
|
|
|
|
if (_tempNewProfileName != "")
|
|
{
|
|
SelectProfileImage(true);
|
|
|
|
if (_bufferImageProfile != null)
|
|
{
|
|
AddUser();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DeleteButton_Pressed(object sender, EventArgs e)
|
|
{
|
|
if (GtkDialog.CreateChoiceDialog("Delete User Profile", "Are you sure you want to delete the profile ?", "Deleting this profile will also delete all associated save data."))
|
|
{
|
|
_accountManager.DeleteUser(GetSelectedUserId());
|
|
|
|
RefreshList();
|
|
}
|
|
}
|
|
|
|
private void EditProfileNameButton_Pressed(object sender, EventArgs e)
|
|
{
|
|
_saveProfileNameButton.Sensitive = false;
|
|
|
|
_accountManager.SetUserName(GetSelectedUserId(), _selectedUserNameEntry.Text);
|
|
|
|
RefreshList();
|
|
}
|
|
|
|
private void ProcessProfileImage(byte[] buffer)
|
|
{
|
|
using (Image image = Image.Load(buffer))
|
|
{
|
|
image.Mutate(x => x.Resize(256, 256));
|
|
|
|
using (MemoryStream streamJpg = new MemoryStream())
|
|
{
|
|
image.SaveAsJpeg(streamJpg);
|
|
|
|
_bufferImageProfile = streamJpg.ToArray();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProfileImageFileChooser()
|
|
{
|
|
FileChooserNative fileChooser = new FileChooserNative("Import Custom Profile Image", this, FileChooserAction.Open, "Import", "Cancel")
|
|
{
|
|
SelectMultiple = false
|
|
};
|
|
|
|
FileFilter filter = new FileFilter()
|
|
{
|
|
Name = "Custom Profile Images"
|
|
};
|
|
filter.AddPattern("*.jpg");
|
|
filter.AddPattern("*.jpeg");
|
|
filter.AddPattern("*.png");
|
|
filter.AddPattern("*.bmp");
|
|
|
|
fileChooser.AddFilter(filter);
|
|
|
|
if (fileChooser.Run() == (int)ResponseType.Accept)
|
|
{
|
|
ProcessProfileImage(File.ReadAllBytes(fileChooser.Filename));
|
|
}
|
|
|
|
fileChooser.Dispose();
|
|
}
|
|
|
|
private void SelectProfileImage(bool newUser = false)
|
|
{
|
|
if (_contentManager.GetCurrentFirmwareVersion() == null)
|
|
{
|
|
ProfileImageFileChooser();
|
|
}
|
|
else
|
|
{
|
|
Dictionary<int, string> buttons = new Dictionary<int, string>()
|
|
{
|
|
{ 0, "Import Image File" },
|
|
{ 1, "Select Firmware Avatar" }
|
|
};
|
|
|
|
ResponseType responseDialog = GtkDialog.CreateCustomDialog("Profile Image Selection",
|
|
"Choose a Profile Image",
|
|
"You may import a custom profile image, or select an avatar from the system firmware.",
|
|
buttons, MessageType.Question);
|
|
|
|
if (responseDialog == 0)
|
|
{
|
|
ProfileImageFileChooser();
|
|
}
|
|
else if (responseDialog == (ResponseType)1)
|
|
{
|
|
AvatarWindow avatarWindow = new AvatarWindow()
|
|
{
|
|
NewUser = newUser
|
|
};
|
|
|
|
avatarWindow.DeleteEvent += AvatarWindow_DeleteEvent;
|
|
|
|
avatarWindow.SetSizeRequest((int)(avatarWindow.DefaultWidth * Program.WindowScaleFactor), (int)(avatarWindow.DefaultHeight * Program.WindowScaleFactor));
|
|
avatarWindow.Show();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ChangeProfileImageButton_Pressed(object sender, EventArgs e)
|
|
{
|
|
if (_contentManager.GetCurrentFirmwareVersion() != null)
|
|
{
|
|
_avatarsPreloadingEvent.WaitOne();
|
|
}
|
|
|
|
SelectProfileImage();
|
|
|
|
if (_bufferImageProfile != null)
|
|
{
|
|
SetUserImage();
|
|
}
|
|
}
|
|
|
|
private void AvatarWindow_DeleteEvent(object sender, DeleteEventArgs args)
|
|
{
|
|
_bufferImageProfile = ((AvatarWindow)sender).SelectedProfileImage;
|
|
|
|
if (_bufferImageProfile != null)
|
|
{
|
|
if (((AvatarWindow)sender).NewUser)
|
|
{
|
|
AddUser();
|
|
}
|
|
else
|
|
{
|
|
SetUserImage();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void AddUser()
|
|
{
|
|
_accountManager.AddUser(_tempNewProfileName, _bufferImageProfile);
|
|
|
|
_bufferImageProfile = null;
|
|
_tempNewProfileName = "";
|
|
|
|
RefreshList();
|
|
}
|
|
|
|
private void SetUserImage()
|
|
{
|
|
_accountManager.SetUserImage(GetSelectedUserId(), _bufferImageProfile);
|
|
|
|
_bufferImageProfile = null;
|
|
|
|
RefreshList();
|
|
}
|
|
|
|
private UserId GetSelectedUserId()
|
|
{
|
|
if (_usersTreeView.Model.GetIterFirst(out TreeIter iter))
|
|
{
|
|
do
|
|
{
|
|
if ((bool)_tableStore.GetValue(iter, 0))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while (_usersTreeView.Model.IterNext(ref iter));
|
|
}
|
|
|
|
return new UserId(_tableStore.GetValue(iter, 2).ToString().Split("\n")[1]);
|
|
}
|
|
|
|
private void CloseButton_Pressed(object sender, EventArgs e)
|
|
{
|
|
Close();
|
|
}
|
|
}
|
|
} |