[gnome-games/wip/abhinavsingh/gamepad-config] ui/gamepad: Temporary patch for GamepadMapper



commit 2cca1cf5c6e5aeeb098a65528bfd232d56bf40bf
Author: theawless <theawless gmail com>
Date:   Fri May 12 13:32:55 2017 +0530

    ui/gamepad: Temporary patch for GamepadMapper

 data/Makefile.am                         |    1 +
 data/org.gnome.Games.gresource.xml       |    1 +
 data/ui/display-header-bar.ui            |   26 +++++
 data/ui/gamepad-mapper.ui                |   39 +++++++
 src/Makefile.am                          |    3 +
 src/gamepad/gamepad-inverse-mapping.vala |  168 ++++++++++++++++++++++++++++++
 src/ui/display-header-bar.vala           |    8 ++
 src/ui/gamepad-mapper.vala               |  127 ++++++++++++++++++++++
 src/ui/gamepad-view.vala                 |  165 +++++++++++++++++++++++++++++
 9 files changed, 538 insertions(+), 0 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index 87b56b8..71cf862 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -37,6 +37,7 @@ EXTRA_DIST = \
        ui/error-display.ui \
        ui/error-info-bar.ui \
        ui/game-icon-view.ui \
+       ui/gamepad-mapper.ui \
        ui/media-menu-button.ui \
        ui/media-selector.ui \
        ui/preferences-page-plugins-item.ui \
diff --git a/data/org.gnome.Games.gresource.xml b/data/org.gnome.Games.gresource.xml
index e66ccca..cd5c4e2 100644
--- a/data/org.gnome.Games.gresource.xml
+++ b/data/org.gnome.Games.gresource.xml
@@ -16,6 +16,7 @@
     <file preprocess="xml-stripblanks">ui/error-display.ui</file>
     <file preprocess="xml-stripblanks">ui/error-info-bar.ui</file>
     <file preprocess="xml-stripblanks">ui/game-icon-view.ui</file>
+    <file preprocess="xml-stripblanks">ui/gamepad-mapper.ui</file>
     <file preprocess="xml-stripblanks">ui/media-menu-button.ui</file>
     <file preprocess="xml-stripblanks">ui/media-selector.ui</file>
     <file preprocess="xml-stripblanks">ui/preferences-page-plugins.ui</file>
diff --git a/data/ui/display-header-bar.ui b/data/ui/display-header-bar.ui
index aae8f8d..7b15a0a 100644
--- a/data/ui/display-header-bar.ui
+++ b/data/ui/display-header-bar.ui
@@ -83,6 +83,32 @@
       </packing>
     </child>
     <child>
+      <object class="GtkButton" id="gamepad">
+        <property name="visible">True</property>
+        <property name="valign">center</property>
+        <property name="use-underline">True</property>
+        <signal name="clicked" handler="on_gamepad_clicked"/>
+        <style>
+          <class name="image-button"/>
+        </style>
+        <child internal-child="accessible">
+          <object class="AtkObject" id="a11y-gamepad">
+            <property name="accessible-name" translatable="yes">Gamepad</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkImage" id="gamepad_image">
+            <property name="visible">True</property>
+            <property name="icon-name">applications-games-symbolic</property>
+            <property name="icon-size">1</property>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+    <child>
       <object class="GamesMediaMenuButton" id="media_button">
         <property name="visible">False</property>
         <property name="valign">center</property>
diff --git a/data/ui/gamepad-mapper.ui b/data/ui/gamepad-mapper.ui
new file mode 100644
index 0000000..c33c1ce
--- /dev/null
+++ b/data/ui/gamepad-mapper.ui
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GamesGamepadMapper" parent="GtkDialog">
+    <property name="destroy-with-parent">True</property>
+    <property name="type_hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GamesGamepadView" id="gamepad_view">
+            <property name="visible">True</property>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="button_apply">
+        <property name="visible">True</property>
+        <property name="can-default">True</property>
+        <property name="label" translatable="yes">Apply</property>
+        <style>
+          <class name="suggested-action"/>
+        </style>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="button_cancel">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Cancel</property>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="apply" default="true">button_apply</action-widget>
+      <action-widget response="cancel">button_cancel</action-widget>
+    </action-widgets>
+  </template>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c79d92..4792dd9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -77,6 +77,7 @@ gnome_games_SOURCES = \
        gamepad/gamepad.c \
        gamepad/gamepad-dpad.c \
        gamepad/gamepad-input-type.c \
+       gamepad/gamepad-inverse-mapping.vala \
        gamepad/gamepad-mapped-event.c \
        gamepad/gamepad-mapping.c \
        gamepad/gamepad-mapping-error.c \
@@ -123,6 +124,8 @@ gnome_games_SOURCES = \
        ui/error-info-bar.vala \
        ui/game-icon-view.vala \
        ui/game-thumbnail.vala \
+       ui/gamepad-view.vala \
+       ui/gamepad-mapper.vala \
        ui/media-selector.vala \
        ui/media-menu-button.vala \
        ui/preferences-page.vala \
diff --git a/src/gamepad/gamepad-inverse-mapping.vala b/src/gamepad/gamepad-inverse-mapping.vala
new file mode 100644
index 0000000..dffc51a
--- /dev/null
+++ b/src/gamepad/gamepad-inverse-mapping.vala
@@ -0,0 +1,168 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.GamepadInverseMapping : Object {
+       private string[] button_values;
+       private StandardGamepadButton[] button_keys;
+       private string[] axis_values;
+       private StandardGamepadAxis[] axis_keys;
+
+       private string name;
+       private string guid;
+
+       construct {
+               button_values = new string[StandardGamepadButton.size ()];
+               button_keys = StandardGamepadButton.values ();
+       }
+
+       public GamepadInverseMapping (RawGamepad raw_gamepad) {
+               guid = raw_gamepad.guid;
+               name = raw_gamepad.name;
+       }
+
+       public bool add_button_value (int button, int key, GamepadInputType key_type) {
+               var val = parse_button_value (button);
+               switch (key_type) {
+               case GamepadInputType.BUTTON:
+                       if (find_in_values (val, button_values))
+                               return false;
+                       button_values[(StandardGamepadButton) key] = val;
+
+                       return true;
+               case GamepadInputType.AXIS:
+                       return false;
+               case GamepadInputType.INVALID:
+               default:
+                       warning ("Bad key type");
+
+                       return false;
+               }
+       }
+
+       public bool add_axis_value (int axis, int key, GamepadInputType key_type) {
+               switch (key_type) {
+               case GamepadInputType.BUTTON:
+                       return false;
+               case GamepadInputType.AXIS:
+                       return false;;
+               case GamepadInputType.INVALID:
+               default:
+                       warning ("Bad key type");
+
+                       return false;
+               }
+       }
+
+       public bool add_dpad_value (int dpad, int axis, int key, GamepadInputType key_type) {
+               switch (key_type) {
+               case GamepadInputType.BUTTON:
+                       return false;
+               case GamepadInputType.AXIS:
+                       return false;
+               case GamepadInputType.INVALID:
+               default:
+                       warning ("Bad key type");
+
+                       return false;
+               }
+       }
+
+       public string get_sdl_string () {
+               var sdl_string = guid + "," + name + ",";
+               sdl_string += "platform:Linux" + ",";
+
+               for (var i = 0; i < button_keys.length; ++i) {
+                       var key = parse_button (button_keys[i]);
+                       var val = button_values[i];
+                       sdl_string += key + ":" + val + ",";
+               }
+               for (var i = 0; i < axis_keys.length; ++i) {
+                       var key = parse_axis (axis_keys[i]);
+                       var val = axis_values[i];
+                       sdl_string += key + ":" + val + ",";
+               }
+
+               return sdl_string;
+       }
+
+       private static bool find_in_values (string to_find, string[] values) {
+               foreach (var val in values)
+                       if (to_find == val)
+                               return true;
+
+               return false;
+       }
+
+       private static string parse_dpad_value () {
+               return "";
+       }
+
+       private static string parse_axis_value () {
+               return "";
+       }
+
+       private static string parse_axis (StandardGamepadAxis axis) {
+               switch (axis) {
+               case StandardGamepadAxis.LEFT_X:
+                       return "leftx";
+               case StandardGamepadAxis.LEFT_Y:
+                       return "lefty";
+               case StandardGamepadAxis.RIGHT_X:
+                       return "rightx";
+               case StandardGamepadAxis.RIGHT_Y:
+                       return "righty";
+               case StandardGamepadAxis.UNKNOWN:
+               default:
+                       warning (_("Axis is invalid"));
+
+                       return "";
+               }
+       }
+
+       private static string parse_button_value (int button) {
+               return "b" + button.to_string ();
+       }
+
+       private static string parse_button (StandardGamepadButton button) {
+               switch (button) {
+               case StandardGamepadButton.A:
+                       return "a";
+               case StandardGamepadButton.B:
+                       return "b";
+               case StandardGamepadButton.SELECT:
+                       return "back";
+               case StandardGamepadButton.DPAD_DOWN:
+                       return "dpdown";
+               case StandardGamepadButton.DPAD_LEFT:
+                       return "dpleft";
+               case StandardGamepadButton.DPAD_RIGHT:
+                       return "dpright";
+               case StandardGamepadButton.DPAD_UP:
+                       return "dpup";
+               case StandardGamepadButton.HOME:
+                       return "guide";
+               case StandardGamepadButton.SHOULDER_L:
+                       return "leftshoulder";
+               case StandardGamepadButton.STICK_L:
+                       return "leftstick";
+               case StandardGamepadButton.TRIGGER_L:
+                       return "lefttrigger";
+               case StandardGamepadButton.SHOULDER_R:
+                       return "rightshoulder";
+               case StandardGamepadButton.STICK_R:
+                       return "rightstick";
+               case StandardGamepadButton.TRIGGER_R:
+                       return "righttrigger";
+               case StandardGamepadButton.START:
+                       return "start";
+               case StandardGamepadButton.X:
+                       return "x";
+               case StandardGamepadButton.Y:
+                       return "y";
+               case StandardGamepadButton.UNKNOWN:
+               default:
+                       warning (_("Button is invalid"));
+
+                       return "";
+               }
+       }
+}
diff --git a/src/ui/display-header-bar.vala b/src/ui/display-header-bar.vala
index 5fa6749..2fb4688 100644
--- a/src/ui/display-header-bar.vala
+++ b/src/ui/display-header-bar.vala
@@ -61,4 +61,12 @@ private class Games.DisplayHeaderBar : Gtk.HeaderBar {
                is_fullscreen = false;
                settings.set_boolean ("fullscreen", false);
        }
+
+       [GtkCallback]
+       private void on_gamepad_clicked () {
+               var mapper = new GamepadMapper();
+               mapper.set_transient_for ((Gtk.Window) get_toplevel ());
+               mapper.map_gamepad ();
+               mapper.destroy ();
+       }
 }
diff --git a/src/ui/gamepad-mapper.vala b/src/ui/gamepad-mapper.vala
new file mode 100644
index 0000000..6862aef
--- /dev/null
+++ b/src/ui/gamepad-mapper.vala
@@ -0,0 +1,127 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/gamepad-mapper.ui")]
+private class Games.GamepadMapper : Gtk.Dialog {
+       private enum UiState {
+               BEGIN,
+               CONFIGURE,
+               FINISH,
+       }
+
+       [GtkChild]
+       private GamepadView gamepad_view;
+       private Gtk.HeaderBar header_bar;
+
+       private RawGamepad? raw_gamepad;
+       private StandardGamepadButton[] buttons;
+       private StandardGamepadButton current_button;
+       private GamepadInverseMapping inverse_mapping;
+
+       private UiState _ui_state;
+       private UiState ui_state {
+               set {
+                       switch (value) {
+                       case UiState.BEGIN:
+                               header_bar.set_title (_("Press any key on your gamepad"));
+                               set_response_sensitive (Gtk.ResponseType.APPLY, false);
+
+                               break;
+                       case UiState.CONFIGURE:
+                               header_bar.set_title (_("Configuring " + raw_gamepad.name));
+                               prompt_button (current_button);
+
+                               break;
+                       case UiState.FINISH:
+                               header_bar.set_title (_("Finised configuration"));
+                               set_response_sensitive (Gtk.ResponseType.APPLY, true);
+
+                               break;
+                       }
+                       _ui_state = value;
+               }
+               get { return _ui_state; }
+       }
+
+       construct {
+               use_header_bar = 1;
+               header_bar = (Gtk.HeaderBar) get_header_bar ();
+               ui_state = UiState.BEGIN;
+               buttons = StandardGamepadButton.values ();
+               current_button = (StandardGamepadButton) 0;
+               connect_signals ();
+       }
+
+       public void map_gamepad () {
+               // what should be the size?
+               int width, height;
+               var window = get_transient_for ();
+               window.get_size (out width, out height);
+               gamepad_view.set_size_request (width/2, height/2);
+
+               // is this a code smell?
+               var response = run ();
+               message (((Gtk.ResponseType) response).to_string ());
+       }
+
+       private void connect_signals () {
+               var monitor = GamepadMonitor.get_instance ();
+               monitor.foreach_gamepad ((gamepad) => {
+                       var raw_gamepad = gamepad.raw_gamepad;
+                       raw_gamepad.button_event.connect ((button, value) => on_button_event (raw_gamepad, 
button, value));
+                       raw_gamepad.axis_event.connect ((axis, value) => on_axis_event (raw_gamepad, axis, 
value));
+                       raw_gamepad.dpad_event.connect ((dpad, axis, value) => on_dpad_event (raw_gamepad, 
dpad, axis, value));
+               });
+       }
+
+       private void on_button_event (RawGamepad raw_gamepad, int button, bool value) {
+               message (button.to_string ());
+               if (value)
+                       return;
+               if (ui_state == UiState.BEGIN)
+                       start (raw_gamepad);
+               if (raw_gamepad != this.raw_gamepad)
+                       return;
+               var success = inverse_mapping.add_button_value (button, current_button, 
GamepadInputType.BUTTON);
+               message (success.to_string ());
+               if (!success) {
+                       // show some warning like red colors on the gamepad-view
+                       return;
+               }
+               next_button ();
+       }
+
+       private void on_axis_event (RawGamepad raw_gamepad, int axis, double value) {
+               message (axis.to_string ());
+       }
+
+       private void on_dpad_event (RawGamepad raw_gamepad, int dpad, int axis, int value) {
+               message (dpad.to_string () + axis.to_string ());
+       }
+
+       private void start (RawGamepad raw_gamepad) {
+               this.raw_gamepad = raw_gamepad;
+               inverse_mapping = new GamepadInverseMapping (raw_gamepad);
+       }
+
+       private void next_button () {
+               current_button = (StandardGamepadButton) ((int) current_button + 1);
+               if ((int) current_button >= buttons.length) {
+                       ui_state = UiState.FINISH;
+                       finish ();
+                       return;
+               }
+               ui_state = UiState.CONFIGURE;
+       }
+
+       private void finish () {
+               var sdl_string = inverse_mapping.get_sdl_string ();
+               // save using mappings manager
+               message (sdl_string);
+       }
+
+       private void prompt_button (StandardGamepadButton button) {
+               message (button.to_string ());
+               gamepad_view.reset ();
+               gamepad_view.highlight_button (button, true);
+       }
+}
diff --git a/src/ui/gamepad-view.vala b/src/ui/gamepad-view.vala
new file mode 100644
index 0000000..9357b32
--- /dev/null
+++ b/src/ui/gamepad-view.vala
@@ -0,0 +1,165 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.GamepadView : Gtk.DrawingArea {
+       private const double TAU = Math.PI * 2;
+       private const Gtk.StateFlags DEFAULT_STATE = Gtk.StateFlags.NORMAL;
+       private const Gtk.StateFlags HIGHLIGHT_STATE = Gtk.StateFlags.LINK;
+
+       private bool[] button_lightning;
+       private Cairo.Context cr;
+
+       construct {
+               button_lightning = new bool[StandardGamepadButton.size ()];
+       }
+
+       public void highlight_button (StandardGamepadButton button, bool highlight) {
+               button_lightning[button] = highlight;
+               queue_draw ();
+       }
+
+       public void reset () {
+               foreach (var button in StandardGamepadButton.values ()) {
+                       highlight_button (button, false);
+               }
+       }
+
+       private void render (StandardGamepadButton button) {
+               var state = button_lightning[button] ? HIGHLIGHT_STATE : DEFAULT_STATE;
+               var color = get_style_context ().get_color (state);
+               cr.set_source_rgba (color.red, color.green, color.blue, color.alpha);
+
+               cr.fill ();
+       }
+
+       public override bool draw (Cairo.Context cr) {
+               this.cr = cr;
+               var width = get_allocated_width ();
+               var height = get_allocated_height ();
+
+               gamepad (width, height);
+
+               return false;
+       }
+
+       private void gamepad (int width, int height) {
+               double x, y, w, h;
+               if (width * 3 > height * 4) {
+                       // The bounding box is wider than tall
+                       h = (double) height;
+                       w = h * 4/3;
+                       y = 0.0;
+                       x = ((double) width - w) / 2;
+               }
+               else {
+                       // The bounding box is taller than wide
+                       w = (double) width;
+                       h = w * 3/4;
+                       x = 0.0;
+                       y = ((double) height - h) / 2;
+               }
+
+               var mid_h = y + h*0.55;
+
+               dpad (x + w*0.2, mid_h, w*0.2);
+               action_buttons (x + w*0.8, mid_h, w*0.25);
+               control_buttons (x + w/2.0, mid_h, w*0.1);
+               shoulders (x + w/2.0, y + h*0.2, w/5, w/15, w*0.3, w/20);
+               joysticks (x + w/2.0, y + h*0.8, w*0.08, w/3.0);
+       }
+
+       private void dpad (double xc, double yc, double side) {
+               var width = side / 3;
+               var w_shift = side / 6;
+               var l_shift = side / 2;
+
+               // Draw a square in the middle to avoid seeing demaraction lines
+               var color = get_style_context ().get_color (DEFAULT_STATE);
+               cr.set_source_rgba (color.red, color.green, color.blue, color.alpha);
+
+               cr.rectangle (xc - w_shift, yc - w_shift, width, width);
+               cr.fill ();
+
+               cr.move_to (xc, yc);
+               cr.line_to (xc - w_shift, yc - w_shift);
+               cr.line_to (xc - w_shift, yc - l_shift);
+               cr.line_to (xc + w_shift, yc - l_shift);
+               cr.line_to (xc + w_shift, yc - w_shift);
+               cr.line_to (xc, yc);
+               render (StandardGamepadButton.DPAD_UP);
+
+               cr.move_to (xc, yc);
+               cr.line_to (xc - w_shift, yc + w_shift);
+               cr.line_to (xc - w_shift, yc + l_shift);
+               cr.line_to (xc + w_shift, yc + l_shift);
+               cr.line_to (xc + w_shift, yc + w_shift);
+               cr.line_to (xc, yc);
+               render (StandardGamepadButton.DPAD_DOWN);
+
+               cr.move_to (xc, yc);
+               cr.line_to (xc - w_shift, yc - w_shift);
+               cr.line_to (xc - l_shift, yc - w_shift);
+               cr.line_to (xc - l_shift, yc + w_shift);
+               cr.line_to (xc - w_shift, yc + w_shift);
+               cr.line_to (xc, yc);
+               render (StandardGamepadButton.DPAD_LEFT);
+
+               cr.move_to (xc, yc);
+               cr.line_to (xc + w_shift, yc - w_shift);
+               cr.line_to (xc + l_shift, yc - w_shift);
+               cr.line_to (xc + l_shift, yc + w_shift);
+               cr.line_to (xc + w_shift, yc + w_shift);
+               cr.line_to (xc, yc);
+               render (StandardGamepadButton.DPAD_RIGHT);
+       }
+
+       private void action_buttons (double xc, double yc, double side) {
+               var radius = side / 6;
+               var shift = side / 3;
+
+               circle (xc + shift, yc, radius);
+               render (StandardGamepadButton.A);
+               circle (xc - shift, yc, radius);
+               render (StandardGamepadButton.B);
+               circle (xc, yc + shift, radius);
+               render (StandardGamepadButton.X);
+               circle (xc, yc - shift, radius);
+               render (StandardGamepadButton.Y);
+       }
+
+       private void control_buttons (double xc, double yc, double radius) {
+               circle (xc, yc, radius / 2.0);
+               render (StandardGamepadButton.HOME);
+               circle (xc - radius, yc, radius / 3.0);
+               render (StandardGamepadButton.SELECT);
+               circle (xc + radius, yc, radius / 3.0);
+               render (StandardGamepadButton.START);
+       }
+
+       private void shoulders (double xc, double yc, double w, double h, double h_shift, double v_shift) {
+               double h_spacing = h_shift - w / 2.0;
+               double v_spacing = v_shift - h / 2.0;
+
+               cr.rectangle (xc - h_spacing - w, yc + v_spacing, w, h);
+               render (StandardGamepadButton.SHOULDER_L);
+
+               cr.rectangle (xc + h_spacing, yc + v_spacing, w, h);
+               render (StandardGamepadButton.SHOULDER_R);
+
+               cr.rectangle (xc - h_spacing - w, yc - v_spacing - h, w, h);
+               render (StandardGamepadButton.TRIGGER_L);
+
+               cr.rectangle (xc + h_spacing, yc - v_spacing -h, w, h);
+               render (StandardGamepadButton.TRIGGER_R);
+       }
+
+       private void joysticks (double xc, double yc, double radius, double spacing) {
+               circle (xc - spacing/2.0, yc, radius);
+               render (StandardGamepadButton.STICK_L);
+               circle (xc + spacing/2.0, yc, radius);
+               render (StandardGamepadButton.STICK_R);
+       }
+
+       private void circle (double xc, double yc, double radius) {
+               cr.arc (xc, yc, radius, 0, TAU);
+       }
+}


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