[gnome-games/wip/exalm/3ds: 21/21] nintendo-3ds: Support layout switching




commit b65474a0c5e50c9288aaad001d7ce6015cd170dc
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sat Dec 5 18:21:12 2020 +0500

    nintendo-3ds: Support layout switching
    
    Reuse the DS layout switcher.

 plugins/nintendo-3ds/src/meson.build              |   1 +
 plugins/nintendo-3ds/src/nintendo-3ds-plugin.vala |   9 +-
 plugins/nintendo-3ds/src/nintendo-3ds-runner.vala | 144 ++++++++++++++++++++++
 3 files changed, 153 insertions(+), 1 deletion(-)
---
diff --git a/plugins/nintendo-3ds/src/meson.build b/plugins/nintendo-3ds/src/meson.build
index a3daa090..9399dcba 100644
--- a/plugins/nintendo-3ds/src/meson.build
+++ b/plugins/nintendo-3ds/src/meson.build
@@ -1,5 +1,6 @@
 vala_sources = [
   'nintendo-3ds-plugin.vala',
+  'nintendo-3ds-runner.vala',
 ]
 
 c_args = [
diff --git a/plugins/nintendo-3ds/src/nintendo-3ds-plugin.vala 
b/plugins/nintendo-3ds/src/nintendo-3ds-plugin.vala
index 9290e1cf..da868a24 100644
--- a/plugins/nintendo-3ds/src/nintendo-3ds-plugin.vala
+++ b/plugins/nintendo-3ds/src/nintendo-3ds-plugin.vala
@@ -32,7 +32,8 @@ private class Games.Nintendo3DsPlugin : Object, Plugin {
        }
 
        public RunnerFactory[] get_runner_factories () {
-               var factory = new RetroRunnerFactory (platform);
+               var factory = new GenericRunnerFactory (create_runner);
+               factory.add_platform (platform);
 
                return { factory };
        }
@@ -50,6 +51,12 @@ private class Games.Nintendo3DsPlugin : Object, Plugin {
 
                return game;
        }
+
+       private static Runner? create_runner (Game game) throws Error {
+               var core_source = new RetroCoreSource (platform);
+
+               return new Nintendo3DsRunner (game, core_source);
+       }
 }
 
 [ModuleInit]
diff --git a/plugins/nintendo-3ds/src/nintendo-3ds-runner.vala 
b/plugins/nintendo-3ds/src/nintendo-3ds-runner.vala
new file mode 100644
index 00000000..1a7cacc5
--- /dev/null
+++ b/plugins/nintendo-3ds/src/nintendo-3ds-runner.vala
@@ -0,0 +1,144 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.Nintendo3DsRunner : RetroRunner {
+       // Map the 1,2,3,4 key values to the 4 screen layouts of the Nintendo 3DS
+       private static HashTable<uint, ScreenLayout?> layouts;
+
+       private const string SCREENS_LAYOUT_OPTION = "citra_layout_option";
+       private const string PROMINENT_SCREEN_OPTION = "citra_swap_screen";
+
+       private const size_t HEADER_GAME_CODE_OFFSET = 12;
+       private const size_t HEADER_GAME_CODE_SIZE = 3;
+
+       private ScreenLayout _screen_layout;
+       public ScreenLayout screen_layout {
+               get { return _screen_layout; }
+               set {
+                       _screen_layout = value;
+                       update_screen_layout ();
+               }
+       }
+
+       private bool _view_bottom_screen;
+       public bool view_bottom_screen {
+               get { return _view_bottom_screen; }
+               set {
+                       _view_bottom_screen = value;
+                       update_screen_layout ();
+               }
+       }
+
+       static construct {
+               layouts = new HashTable<uint, ScreenLayout?> (direct_hash, direct_equal);
+
+               layouts[Gdk.Key.@1] = ScreenLayout.TOP_BOTTOM;
+               layouts[Gdk.Key.@2] = ScreenLayout.LEFT_RIGHT;
+               layouts[Gdk.Key.@3] = ScreenLayout.RIGHT_LEFT;
+               layouts[Gdk.Key.@4] = ScreenLayout.QUICK_SWITCH;
+       }
+
+       public Nintendo3DsRunner (Game game, RetroCoreSource source) {
+               base.from_source (game, source);
+       }
+
+       private bool core_supports_layouts () {
+               var core = get_core ();
+
+               return core != null && core.has_option (SCREENS_LAYOUT_OPTION) && core.has_option 
(PROMINENT_SCREEN_OPTION);
+       }
+
+       public string get_layout_option_value (ScreenLayout layout) {
+               switch (layout) {
+               case TOP_BOTTOM:
+                       return "Default Top-Bottom Screen";
+
+               case LEFT_RIGHT:
+               case RIGHT_LEFT:
+                       return "Side by Side";
+
+               case QUICK_SWITCH:
+                       return "Single Screen Only";
+
+               default:
+                       assert_not_reached ();
+               }
+       }
+
+       private void update_screen_layout () {
+               if (!core_supports_layouts ())
+                       return;
+
+               var core = get_core ();
+
+               var screens_layout_option = core.get_option (SCREENS_LAYOUT_OPTION);
+               var prominent_screen_option = core.get_option (PROMINENT_SCREEN_OPTION);
+
+               var screens_layout_option_value = get_layout_option_value (screen_layout);
+               bool use_bottom_screen = false;
+
+               if (screen_layout == ScreenLayout.RIGHT_LEFT)
+                       use_bottom_screen = true;
+
+               if (screen_layout == ScreenLayout.QUICK_SWITCH)
+                       use_bottom_screen = view_bottom_screen;
+
+               try {
+                       screens_layout_option.set_value (screens_layout_option_value);
+                       prominent_screen_option.set_value (use_bottom_screen ? "Bottom" : "Top");
+               }
+               catch (Error e) {
+                       critical ("Failed to set desmume option: %s", e.message);
+               }
+       }
+
+       public override HeaderBarWidget? get_extra_widget () {
+               if (!core_supports_layouts ())
+                       return null;
+
+               var switcher = new ScreenLayoutSwitcher ();
+
+               bind_property ("screen-layout", switcher, "screen-layout",
+                              BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+               bind_property ("view-bottom-screen", switcher, "view-bottom-screen",
+                              BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+
+               return switcher;
+       }
+
+       public override bool key_press_event (uint keyval, Gdk.ModifierType state) {
+               if (state == Gdk.ModifierType.MOD1_MASK) {
+                       // Alt + 1|2|3|4
+                       var shortcut_layout = layouts[keyval];
+                       if (shortcut_layout != null) {
+                               screen_layout = shortcut_layout;
+
+                               return true;
+                       }
+               }
+
+               if (screen_layout != ScreenLayout.QUICK_SWITCH)
+                       return false;
+
+               var switch_keyval = view_bottom_screen ? Gdk.Key.Page_Up : Gdk.Key.Page_Down;
+               if (keyval == switch_keyval)
+                       return swap_screens ();
+
+               return false;
+       }
+
+       public override bool gamepad_button_press_event (uint16 button) {
+               if (button == EventCode.BTN_THUMBR)
+                       return swap_screens ();
+
+               return false;
+       }
+
+       private bool swap_screens () {
+               if (screen_layout != ScreenLayout.QUICK_SWITCH)
+                       return false;
+
+               view_bottom_screen = !view_bottom_screen;
+
+               return true;
+       }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]