diff options
author | mageven <62494521+mageven@users.noreply.github.com> | 2020-08-03 07:00:58 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-03 03:30:58 +0200 |
commit | c11855565e0ce2bac228610cbaa92c8c7f082c70 (patch) | |
tree | 76f4ee1c3c4c15997d27c9cf8d963bac4405c915 /Ryujinx/Ui | |
parent | f0c91d9efb7eff0b8bbe8fc8d4901af5a9d59005 (diff) |
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
Diffstat (limited to 'Ryujinx/Ui')
-rw-r--r-- | Ryujinx/Ui/GtkHostUiHandler.cs | 69 | ||||
-rw-r--r-- | Ryujinx/Ui/InputDialog.cs | 69 | ||||
-rw-r--r-- | Ryujinx/Ui/MainWindow.cs | 9 |
3 files changed, 146 insertions, 1 deletions
diff --git a/Ryujinx/Ui/GtkHostUiHandler.cs b/Ryujinx/Ui/GtkHostUiHandler.cs new file mode 100644 index 00000000..7b7b3647 --- /dev/null +++ b/Ryujinx/Ui/GtkHostUiHandler.cs @@ -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; + } + } +} diff --git a/Ryujinx/Ui/InputDialog.cs b/Ryujinx/Ui/InputDialog.cs new file mode 100644 index 00000000..a8dc80bf --- /dev/null +++ b/Ryujinx/Ui/InputDialog.cs @@ -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); + } + } +}
\ No newline at end of file diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 42870107..2e288ac9 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -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(); |