diff options
Diffstat (limited to 'Ryujinx/Ui/Applet')
-rw-r--r-- | Ryujinx/Ui/Applet/ErrorAppletDialog.cs | 27 | ||||
-rw-r--r-- | Ryujinx/Ui/Applet/GtkHostUiHandler.cs | 190 | ||||
-rw-r--r-- | Ryujinx/Ui/Applet/SwkbdAppletDialog.cs | 89 |
3 files changed, 306 insertions, 0 deletions
diff --git a/Ryujinx/Ui/Applet/ErrorAppletDialog.cs b/Ryujinx/Ui/Applet/ErrorAppletDialog.cs new file mode 100644 index 00000000..a51d5324 --- /dev/null +++ b/Ryujinx/Ui/Applet/ErrorAppletDialog.cs @@ -0,0 +1,27 @@ +using Gtk; + +namespace Ryujinx.Ui.Applet +{ + internal class ErrorAppletDialog : MessageDialog + { + public ErrorAppletDialog(Window parentWindow, DialogFlags dialogFlags, MessageType messageType, string[] buttons) : base(parentWindow, dialogFlags, messageType, ButtonsType.None, null) + { + int responseId = 0; + + if (buttons != null) + { + foreach (string buttonText in buttons) + { + AddButton(buttonText, responseId); + responseId++; + } + } + else + { + AddButton("OK", 0); + } + + ShowAll(); + } + } +}
\ No newline at end of file diff --git a/Ryujinx/Ui/Applet/GtkHostUiHandler.cs b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs new file mode 100644 index 00000000..804a1a27 --- /dev/null +++ b/Ryujinx/Ui/Applet/GtkHostUiHandler.cs @@ -0,0 +1,190 @@ +using Gtk; +using Ryujinx.HLE; +using Ryujinx.HLE.HOS.Applets; +using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; +using Ryujinx.Ui.Widgets; +using System; +using System.Threading; + +namespace Ryujinx.Ui.Applet +{ + internal class GtkHostUiHandler : IHostUiHandler + { + private readonly Window _parent; + + public GtkHostUiHandler(Window parent) + { + _parent = parent; + } + + public bool DisplayMessageDialog(ControllerAppletUiArgs args) + { + string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; + + string message = $"Application requests <b>{playerCount}</b> player(s) with:\n\n" + + $"<tt><b>TYPES:</b> {args.SupportedStyles}</tt>\n\n" + + $"<tt><b>PLAYERS:</b> {string.Join(", ", args.SupportedPlayers)}</tt>\n\n" + + (args.IsDocked ? "Docked mode set. <tt>Handheld</tt> is also invalid.\n\n" : "") + + "<i>Please reconfigure Input now and then press OK.</i>"; + + return DisplayMessageDialog("Controller Applet", message); + } + + public bool DisplayMessageDialog(string title, string message) + { + ManualResetEvent dialogCloseEvent = new ManualResetEvent(false); + + bool okPressed = false; + + Application.Invoke(delegate + { + MessageDialog msgDialog = null; + + try + { + msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null) + { + Title = title, + Text = message, + UseMarkup = true + }; + + msgDialog.SetDefaultSize(400, 0); + + msgDialog.Response += (object o, ResponseArgs args) => + { + if (args.ResponseId == ResponseType.Ok) + { + okPressed = true; + } + + dialogCloseEvent.Set(); + msgDialog?.Dispose(); + }; + + msgDialog.Show(); + } + catch (Exception ex) + { + GtkDialog.CreateErrorDialog($"Error displaying Message Dialog: {ex}"); + + dialogCloseEvent.Set(); + } + }); + + dialogCloseEvent.WaitOne(); + + return okPressed; + } + + 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 SwkbdAppletDialog(_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 ex) + { + error = true; + + GtkDialog.CreateErrorDialog($"Error displaying Software Keyboard: {ex}"); + } + finally + { + dialogCloseEvent.Set(); + } + }); + + dialogCloseEvent.WaitOne(); + + userText = error ? null : inputText; + + return error || okPressed; + } + + public void ExecuteProgram(HLE.Switch device, ProgramSpecifyKind kind, ulong value) + { + device.UserChannelPersistence.ExecuteProgram(kind, value); + ((MainWindow)_parent).GlRendererWidget?.Exit(); + } + + public bool DisplayErrorAppletDialog(string title, string message, string[] buttons) + { + ManualResetEvent dialogCloseEvent = new ManualResetEvent(false); + + bool showDetails = false; + + Application.Invoke(delegate + { + try + { + ErrorAppletDialog msgDialog = new ErrorAppletDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Error, buttons) + { + Title = title, + Text = message, + UseMarkup = true, + WindowPosition = WindowPosition.CenterAlways + }; + + msgDialog.SetDefaultSize(400, 0); + + msgDialog.Response += (object o, ResponseArgs args) => + { + if (buttons != null) + { + if (buttons.Length > 1) + { + if (args.ResponseId != (ResponseType)(buttons.Length - 1)) + { + showDetails = true; + } + } + } + + dialogCloseEvent.Set(); + msgDialog?.Dispose(); + }; + + msgDialog.Show(); + } + catch (Exception ex) + { + GtkDialog.CreateErrorDialog($"Error displaying ErrorApplet Dialog: {ex}"); + + dialogCloseEvent.Set(); + } + }); + + dialogCloseEvent.WaitOne(); + + return showDetails; + } + } +}
\ No newline at end of file diff --git a/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs b/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs new file mode 100644 index 00000000..7c14f0e8 --- /dev/null +++ b/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs @@ -0,0 +1,89 @@ +using Gtk; +using System; + +namespace Ryujinx.Ui.Applet +{ + public class SwkbdAppletDialog : MessageDialog + { + private int _inputMin; + private int _inputMax; + + private Predicate<int> _checkLength; + + private readonly Label _validationInfo; + + public Entry InputEntry { get; } + public Button OkButton { get; } + public Button CancelButton { get; } + + public SwkbdAppletDialog(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 += OnInputActivated; + 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 OnInputActivated(object sender, EventArgs e) + { + if (OkButton.IsSensitive) + { + Respond(ResponseType.Ok); + } + } + + private void OnInputChanged(object sender, EventArgs e) + { + OkButton.Sensitive = _checkLength(InputEntry.Text.Length); + } + } +}
\ No newline at end of file |