From ec6cb0abb4b7669895b6e96fd7581c93b5abd691 Mon Sep 17 00:00:00 2001
From: Mary Guillemard <mary@mary.zone>
Date: Sat, 2 Mar 2024 12:51:05 +0100
Subject: infra: Make Avalonia the default UI  (#6375)

* misc: Move Ryujinx project to Ryujinx.Gtk3

This breaks release CI for now but that's fine.

Signed-off-by: Mary Guillemard <mary@mary.zone>

* misc: Move Ryujinx.Ava project to Ryujinx

This breaks CI for now, but it's fine.

Signed-off-by: Mary Guillemard <mary@mary.zone>

* infra: Make Avalonia the default UI

Should fix CI after the previous changes.

GTK3 isn't build by the release job anymore, only by PR CI.

This also ensure that the test-ava update package is still generated to
allow update from the old testing channel.

Signed-off-by: Mary Guillemard <mary@mary.zone>

* Fix missing copy in create_app_bundle.sh

Signed-off-by: Mary Guillemard <mary@mary.zone>

* Fix syntax error

Signed-off-by: Mary Guillemard <mary@mary.zone>

---------

Signed-off-by: Mary Guillemard <mary@mary.zone>
---
 .../UI/Applet/GtkDynamicTextInputHandler.cs        | 108 +++++++++++++++++++++
 1 file changed, 108 insertions(+)
 create mode 100644 src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs

(limited to 'src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs')

diff --git a/src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs b/src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs
new file mode 100644
index 00000000..0e560b78
--- /dev/null
+++ b/src/Ryujinx.Gtk3/UI/Applet/GtkDynamicTextInputHandler.cs
@@ -0,0 +1,108 @@
+using Gtk;
+using Ryujinx.HLE.UI;
+using Ryujinx.Input.GTK3;
+using Ryujinx.UI.Widgets;
+using System.Threading;
+
+namespace Ryujinx.UI.Applet
+{
+    /// <summary>
+    /// Class that forwards key events to a GTK Entry so they can be processed into text.
+    /// </summary>
+    internal class GtkDynamicTextInputHandler : IDynamicTextInputHandler
+    {
+        private readonly Window _parent;
+        private readonly OffscreenWindow _inputToTextWindow = new();
+        private readonly RawInputToTextEntry _inputToTextEntry = new();
+
+        private bool _canProcessInput;
+
+        public event DynamicTextChangedHandler TextChangedEvent;
+        public event KeyPressedHandler KeyPressedEvent;
+        public event KeyReleasedHandler KeyReleasedEvent;
+
+        public bool TextProcessingEnabled
+        {
+            get
+            {
+                return Volatile.Read(ref _canProcessInput);
+            }
+
+            set
+            {
+                Volatile.Write(ref _canProcessInput, value);
+            }
+        }
+
+        public GtkDynamicTextInputHandler(Window parent)
+        {
+            _parent = parent;
+            _parent.KeyPressEvent += HandleKeyPressEvent;
+            _parent.KeyReleaseEvent += HandleKeyReleaseEvent;
+
+            _inputToTextWindow.Add(_inputToTextEntry);
+
+            _inputToTextEntry.TruncateMultiline = true;
+
+            // Start with input processing turned off so the text box won't accumulate text 
+            // if the user is playing on the keyboard.
+            _canProcessInput = false;
+        }
+
+        [GLib.ConnectBefore()]
+        private void HandleKeyPressEvent(object o, KeyPressEventArgs args)
+        {
+            var key = (Ryujinx.Common.Configuration.Hid.Key)GTK3MappingHelper.ToInputKey(args.Event.Key);
+
+            if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
+            {
+                return;
+            }
+
+            if (_canProcessInput)
+            {
+                _inputToTextEntry.SendKeyPressEvent(o, args);
+                _inputToTextEntry.GetSelectionBounds(out int selectionStart, out int selectionEnd);
+                TextChangedEvent?.Invoke(_inputToTextEntry.Text, selectionStart, selectionEnd, _inputToTextEntry.OverwriteMode);
+            }
+        }
+
+        [GLib.ConnectBefore()]
+        private void HandleKeyReleaseEvent(object o, KeyReleaseEventArgs args)
+        {
+            var key = (Ryujinx.Common.Configuration.Hid.Key)GTK3MappingHelper.ToInputKey(args.Event.Key);
+
+            if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
+            {
+                return;
+            }
+
+            if (_canProcessInput)
+            {
+                // TODO (caian): This solution may have problems if the pause is sent after a key press
+                // and before a key release. But for now GTK Entry does not seem to use release events.
+                _inputToTextEntry.SendKeyReleaseEvent(o, args);
+                _inputToTextEntry.GetSelectionBounds(out int selectionStart, out int selectionEnd);
+                TextChangedEvent?.Invoke(_inputToTextEntry.Text, selectionStart, selectionEnd, _inputToTextEntry.OverwriteMode);
+            }
+        }
+
+        public void SetText(string text, int cursorBegin)
+        {
+            _inputToTextEntry.Text = text;
+            _inputToTextEntry.Position = cursorBegin;
+        }
+
+        public void SetText(string text, int cursorBegin, int cursorEnd)
+        {
+            _inputToTextEntry.Text = text;
+            _inputToTextEntry.SelectRegion(cursorBegin, cursorEnd);
+        }
+
+        public void Dispose()
+        {
+            _parent.KeyPressEvent -= HandleKeyPressEvent;
+            _parent.KeyReleaseEvent -= HandleKeyReleaseEvent;
+        }
+    }
+}
-- 
cgit v1.2.3-70-g09d2