Implement Software Keyboard GTK frontend (#1434)
* Implement SwKbd GUI * Relocate UI handler to Emu Context from Config Also create a common interface for UI handlers in the context and specialize for Gtk Add basic input length validation in InputDialog * Add Transfer Memory support to AppletCreator Read Initial Text for SwKbd using Transfer Memory * Improve InputDialog widget Improve length validation Has extra label to show validition info Handle potential errors and log them * Misc improvements * Improve string validation * Improve error handling * Remove tuple in struct * Address formatting nits * Add proper Cancel functionality Also handle GUI errors in UI handler * Address jD's comments * Fix _uiHandler init * Address AcK's comments
This commit is contained in:
parent
f0c91d9efb
commit
c11855565e
8 changed files with 245 additions and 15 deletions
69
Ryujinx/Ui/GtkHostUiHandler.cs
Normal file
69
Ryujinx/Ui/GtkHostUiHandler.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using Gtk;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
internal class GtkHostUiHandler : IHostUiHandler
|
||||
{
|
||||
private readonly Window _parent;
|
||||
|
||||
public GtkHostUiHandler(Window parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
|
||||
{
|
||||
ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);
|
||||
bool okPressed = false;
|
||||
bool error = false;
|
||||
string inputText = args.InitialText ?? "";
|
||||
|
||||
Application.Invoke(delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
var swkbdDialog = new InputDialog(_parent)
|
||||
{
|
||||
Title = "Software Keyboard",
|
||||
Text = args.HeaderText,
|
||||
SecondaryText = args.SubtitleText
|
||||
};
|
||||
|
||||
swkbdDialog.InputEntry.Text = inputText;
|
||||
swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
|
||||
swkbdDialog.OkButton.Label = args.SubmitText;
|
||||
|
||||
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
|
||||
|
||||
if (swkbdDialog.Run() == (int)ResponseType.Ok)
|
||||
{
|
||||
inputText = swkbdDialog.InputEntry.Text;
|
||||
okPressed = true;
|
||||
}
|
||||
|
||||
swkbdDialog.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = true;
|
||||
Logger.PrintError(LogClass.Application, $"Error displaying Software Keyboard: {e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
dialogCloseEvent.Set();
|
||||
}
|
||||
});
|
||||
|
||||
dialogCloseEvent.WaitOne();
|
||||
|
||||
userText = error ? null : inputText;
|
||||
|
||||
return error || okPressed;
|
||||
}
|
||||
}
|
||||
}
|
69
Ryujinx/Ui/InputDialog.cs
Normal file
69
Ryujinx/Ui/InputDialog.cs
Normal file
|
@ -0,0 +1,69 @@
|
|||
using Gtk;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ui
|
||||
{
|
||||
public class InputDialog : MessageDialog
|
||||
{
|
||||
private int _inputMin, _inputMax;
|
||||
private Predicate<int> _checkLength;
|
||||
private Label _validationInfo;
|
||||
|
||||
public Entry InputEntry { get; }
|
||||
public Button OkButton { get; }
|
||||
public Button CancelButton { get; }
|
||||
|
||||
public InputDialog(Window parent)
|
||||
: base(parent, DialogFlags.Modal | DialogFlags.DestroyWithParent, MessageType.Question, ButtonsType.None, null)
|
||||
{
|
||||
SetDefaultSize(300, 0);
|
||||
|
||||
_validationInfo = new Label() { Visible = false };
|
||||
|
||||
InputEntry = new Entry() { Visible = true };
|
||||
InputEntry.Activated += (object sender, EventArgs e) => { if (OkButton.IsSensitive) Respond(ResponseType.Ok); };
|
||||
InputEntry.Changed += OnInputChanged;
|
||||
|
||||
OkButton = (Button)AddButton("OK", ResponseType.Ok);
|
||||
CancelButton = (Button)AddButton("Cancel", ResponseType.Cancel);
|
||||
|
||||
((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
|
||||
((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
|
||||
|
||||
SetInputLengthValidation(0, int.MaxValue); // disable by default
|
||||
}
|
||||
|
||||
public void SetInputLengthValidation(int min, int max)
|
||||
{
|
||||
_inputMin = Math.Min(min, max);
|
||||
_inputMax = Math.Max(min, max);
|
||||
|
||||
_validationInfo.Visible = false;
|
||||
|
||||
if (_inputMin <= 0 && _inputMax == int.MaxValue) // disable
|
||||
{
|
||||
_validationInfo.Visible = false;
|
||||
_checkLength = (length) => true;
|
||||
}
|
||||
else if (_inputMin > 0 && _inputMax == int.MaxValue)
|
||||
{
|
||||
_validationInfo.Visible = true;
|
||||
_validationInfo.Markup = $"<i>Must be at least {_inputMin} characters long</i>";
|
||||
_checkLength = (length) => _inputMin <= length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_validationInfo.Visible = true;
|
||||
_validationInfo.Markup = $"<i>Must be {_inputMin}-{_inputMax} characters long</i>";
|
||||
_checkLength = (length) => _inputMin <= length && length <= _inputMax;
|
||||
}
|
||||
|
||||
OnInputChanged(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnInputChanged(object sender, EventArgs e)
|
||||
{
|
||||
OkButton.Sensitive = _checkLength(InputEntry.Text.Length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using LibHac.Ns;
|
|||
using Ryujinx.Audio;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Configuration;
|
||||
using Ryujinx.Configuration.System;
|
||||
using Ryujinx.Debugger.Profiler;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
|
@ -31,6 +32,7 @@ namespace Ryujinx.Ui
|
|||
private static HLE.Switch _emulationContext;
|
||||
|
||||
private static GlRenderer _glWidget;
|
||||
private static GtkHostUiHandler _uiHandler;
|
||||
|
||||
private static AutoResetEvent _deviceExitStatus = new AutoResetEvent(false);
|
||||
|
||||
|
@ -191,6 +193,8 @@ namespace Ryujinx.Ui
|
|||
Task.Run(RefreshFirmwareLabel);
|
||||
|
||||
_statusBar.Hide();
|
||||
|
||||
_uiHandler = new GtkHostUiHandler(this);
|
||||
}
|
||||
|
||||
private void MainWindow_WindowStateEvent(object o, WindowStateEventArgs args)
|
||||
|
@ -318,7 +322,10 @@ namespace Ryujinx.Ui
|
|||
{
|
||||
_virtualFileSystem.Reload();
|
||||
|
||||
HLE.Switch instance = new HLE.Switch(_virtualFileSystem, _contentManager, InitializeRenderer(), InitializeAudioEngine());
|
||||
HLE.Switch instance = new HLE.Switch(_virtualFileSystem, _contentManager, InitializeRenderer(), InitializeAudioEngine())
|
||||
{
|
||||
UiHandler = _uiHandler
|
||||
};
|
||||
|
||||
instance.Initialize();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue