[gnome-games/wip/abhinavsingh/gamepad-config: 20/23] ui: Add GamepadMapper



commit 5560375dc759c6146a16e15b6aaf1d64958aa904
Author: theawless <theawless gmail com>
Date:   Sun May 28 14:55:59 2017 +0530

    ui: Add GamepadMapper
    
    GamepadMapper uses GamepadView to get the user input,
    GamepadMappingBuilder to build the sdl string from those inputs and
    save it using GamepadMappingsManager.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=780754

 data/Makefile.am                   |    1 +
 data/org.gnome.Games.gresource.xml |    1 +
 data/ui/gamepad-mapper.ui          |  105 +++++++++++++++
 src/Makefile.am                    |    1 +
 src/ui/gamepad-mapper.vala         |  258 ++++++++++++++++++++++++++++++++++++
 5 files changed, 366 insertions(+), 0 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index cf1b58b..5f3d675 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -37,6 +37,7 @@ EXTRA_DIST = \
        ui/empty-collection.ui \
        ui/error-display.ui \
        ui/error-info-bar.ui \
+       ui/gamepad-mapper.ui \
        ui/game-icon-view.ui \
        ui/media-menu-button.ui \
        ui/media-selector.ui \
diff --git a/data/org.gnome.Games.gresource.xml b/data/org.gnome.Games.gresource.xml
index 9e14d6f..49a7af4 100644
--- a/data/org.gnome.Games.gresource.xml
+++ b/data/org.gnome.Games.gresource.xml
@@ -16,6 +16,7 @@
     <file preprocess="xml-stripblanks">ui/empty-collection.ui</file>
     <file preprocess="xml-stripblanks">ui/error-display.ui</file>
     <file preprocess="xml-stripblanks">ui/error-info-bar.ui</file>
+    <file preprocess="xml-stripblanks">ui/gamepad-mapper.ui</file>
     <file preprocess="xml-stripblanks">ui/game-icon-view.ui</file>
     <file preprocess="xml-stripblanks">ui/media-menu-button.ui</file>
     <file preprocess="xml-stripblanks">ui/media-selector.ui</file>
diff --git a/data/ui/gamepad-mapper.ui b/data/ui/gamepad-mapper.ui
new file mode 100644
index 0000000..673f8c6
--- /dev/null
+++ b/data/ui/gamepad-mapper.ui
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GamesGamepadMapper" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">6</property>
+    <property name="margin-top">12</property>
+    <property name="margin-bottom">12</property>
+    <property name="margin-start">48</property>
+    <property name="margin-end">48</property>
+    <child>
+      <object class="GtkLabel" id="info_message">
+        <property name="visible">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel" id="error_message">
+        <property name="visible">True</property>
+        <attributes>
+          <attribute name="foreground" value="red"/>
+        </attributes>
+      </object>
+    </child>
+    <child>
+      <object class="GamesGamepadView" id="gamepad_view">
+        <property name="halign">center</property>
+        <property name="visible">True</property>
+        <property name="halign">fill</property>
+        <property name="valign">fill</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+      </object>
+    </child>
+  </template>
+  <object class="GtkBox" id="header_content">
+    <property name="orientation">horizontal</property>
+    <property name="visible">True</property>
+    <property name="spacing">2</property>
+    <property name="hexpand">True</property>
+    <child>
+      <object class="GtkButton" id="back_button">
+        <property name="visible">True</property>
+        <signal name="clicked" handler="on_back_clicked"/>
+        <style>
+          <class name="image-button"/>
+        </style>
+        <child internal-child="accessible">
+          <object class="AtkObject" id="a11y-back">
+            <property name="accessible-name" translatable="yes">Back</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkImage" id="back_image">
+            <property name="visible">True</property>
+            <property name="icon-name">go-previous-symbolic</property>
+            <property name="icon-size">1</property>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="pack-type">start</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="reset_button">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Reset</property>
+        <signal name="clicked" handler="on_reset_clicked"/>
+      </object>
+      <packing>
+        <property name="pack-type">start</property>
+      </packing>
+    </child>
+    <child type="center">
+      <object class="GtkLabel" id="title">
+        <property name="visible">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkButton" id="apply_button">
+        <property name="visible">True</property>
+        <property name="can-default">True</property>
+        <property name="label" translatable="yes">Apply</property>
+        <signal name="clicked" handler="on_apply_clicked"/>
+        <style>
+          <class name="suggested-action"/>
+        </style>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="skip_button">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Skip</property>
+        <signal name="clicked" handler="on_skip_clicked"/>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index 40def28..43cf66b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -129,6 +129,7 @@ gnome_games_SOURCES = \
        ui/empty-collection.vala \
        ui/error-display.vala \
        ui/error-info-bar.vala \
+       ui/gamepad-mapper.vala \
        ui/gamepad-view.vala \
        ui/game-icon-view.vala \
        ui/game-thumbnail.vala \
diff --git a/src/ui/gamepad-mapper.vala b/src/ui/gamepad-mapper.vala
new file mode 100644
index 0000000..ef58916
--- /dev/null
+++ b/src/ui/gamepad-mapper.vala
@@ -0,0 +1,258 @@
+// 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.Box {
+       public signal void back ();
+
+       private enum State {
+               BEGIN,
+               CONFIGURE,
+               FINISH,
+       }
+
+       private State? _state;
+       private State? state {
+               set {
+                       error_message.label = "";
+                       if (value == _state)
+                               return;
+
+                       switch (value) {
+                       case State.BEGIN:
+                               apply_button.set_sensitive (false);
+                               title.label = _("Configuring ") + gamepad.name;
+                               connect_to_gamepad ();
+
+                               break;
+                       case State.CONFIGURE:
+                               break;
+                       case State.FINISH:
+                               skip_button.set_sensitive (false);
+                               apply_button.set_sensitive (true);
+                               title.label = _("Finished configuration");
+                               disconnect_from_gamepad ();
+
+                               break;
+                       }
+
+                       _state = value;
+               }
+               get { return _state; }
+       }
+
+       private GamepadInput? _input;
+       private GamepadInput? input {
+               set {
+                       _input = value;
+                       if (_input == null) {
+                               info_message.label = "";
+
+                               return;
+                       }
+
+                       switch (input.type) {
+                       case EventCode.EV_KEY:
+                               info_message.label = _("Press suitable button on your gamepad");
+
+                               break;
+                       case EventCode.EV_ABS:
+                               if (input.code == EventCode.ABS_X || input.code == EventCode.ABS_RX)
+                                       info_message.label = _("Move suitable axis left/right on your 
gamepad");
+                               else if (input.code == EventCode.ABS_Y || input.code == EventCode.ABS_RY)
+                                       info_message.label = _("Move suitable axis up/down on your gamepad");
+
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               get { return _input; }
+
+       }
+
+       [GtkChild]
+       private Gtk.Label info_message;
+       [GtkChild]
+       private Gtk.Label error_message;
+       [GtkChild]
+       private GamepadView gamepad_view;
+       [GtkChild]
+       public Gtk.Box header_content;
+       [GtkChild]
+       private Gtk.Button apply_button;
+       [GtkChild]
+       private Gtk.Button skip_button;
+       [GtkChild]
+       private Gtk.Label title;
+
+       private Gamepad gamepad;
+       private GamepadMappingBuilder mapping_builder;
+       private ulong gamepad_event_handler_id;
+       private uint error_message_hider_id;
+
+       construct {
+               error_message.notify["label"].connect (() => {
+                       if (error_message.label != "")
+                               error_message_hide ();
+               });
+       }
+
+       public GamepadMapper (Gamepad gamepad) {
+               this.gamepad = gamepad;
+               mapping_builder = new GamepadMappingBuilder ();
+               state = State.BEGIN;
+       }
+
+       private void error_message_hide () {
+               if (error_message_hider_id > 0) {
+                       GLib.Source.remove (error_message_hider_id);
+               }
+               error_message_hider_id = GLib.Timeout.add (2000, () => {
+                       error_message_hider_id = 0;
+                       if (error_message != null)
+                               error_message.label = "";
+
+                       return false;
+               });
+       }
+
+       public void start () {
+               next_input ();
+       }
+
+       [GtkCallback]
+       private void on_apply_clicked () {
+               save_mapping ();
+               back ();
+       }
+
+       [GtkCallback]
+       private void on_skip_clicked () {
+               next_input ();
+       }
+
+       [GtkCallback]
+       private void on_reset_clicked () {
+               reset_mapping ();
+               back ();
+       }
+
+       [GtkCallback]
+       private void on_back_clicked () {
+               back ();
+       }
+
+       private void connect_to_gamepad () {
+               gamepad_event_handler_id = this.gamepad.event.connect ((event) => {
+                       switch (event.type) {
+                       case EventType.EVENT_GAMEPAD_BUTTON_RELEASE:
+                               on_button_event (event.gamepad_button);
+
+                               break;
+                       case EventType.EVENT_GAMEPAD_AXIS:
+                               on_axis_event (event.gamepad_axis);
+
+                               break;
+                       case EventType.EVENT_GAMEPAD_HAT:
+                               on_hat_event (event.gamepad_hat);
+
+                               break;
+                       default:
+                               break;
+                       }
+               });
+       }
+
+       private void disconnect_from_gamepad () {
+               gamepad.disconnect (gamepad_event_handler_id);
+       }
+
+       private void on_button_event (EventGamepadButton event) {
+               if (input.type == EventCode.EV_ABS) {
+                       error_message.label = _("This combination is not valid");
+
+                       return;
+               }
+
+               var success = mapping_builder.set_button_mapping (event.gamepad_button.hardware_index,
+                                                                 input);
+               if (!success) {
+                       error_message.label = _("This button is already in use");
+
+                       return;
+               }
+
+               next_input ();
+       }
+
+       private void on_axis_event (EventGamepadAxis event) {
+               if (input.type == EventCode.EV_KEY) {
+                       error_message.label = _("This combination is not valid");
+
+                       return;
+               }
+               if (-0.8 < event.gamepad_axis.value && event.gamepad_axis.value < 0.8)
+                       return;
+
+               var success = mapping_builder.set_axis_mapping (event.gamepad_axis.hardware_index,
+                                                               input);
+               if (!success) {
+                       error_message.label = _("This axis is already in use");
+
+                       return;
+               }
+
+               next_input ();
+       }
+
+       private void on_hat_event (EventGamepadHat event) {
+               if (event.gamepad_hat.value == 0)
+                       return;
+
+               var success = mapping_builder.set_hat_mapping (event.gamepad_hat.hardware_index,
+                                                              event.gamepad_hat.value,
+                                                              event.gamepad_hat.axis,
+                                                              input);
+               if (!success) {
+                       error_message.label = _("This hat is already in use");
+
+                       return;
+               }
+
+               next_input ();
+       }
+
+       private void next_input () {
+               input = gamepad_view.highlight_next ();
+               if (input == null) {
+                       state = State.FINISH;
+
+                       return;
+               }
+
+               state = State.CONFIGURE;
+       }
+
+       private void save_mapping () {
+               var sdl_string = mapping_builder.build_sdl_string ();
+               save_sdl_string (sdl_string);
+       }
+
+       private void reset_mapping () {
+               var mappings_manager = GamepadMappingsManager.get_instance ();
+               var sdl_string =  mappings_manager.get_default_mapping (gamepad.guid);
+               save_sdl_string (sdl_string);
+       }
+
+       private void save_sdl_string (string sdl_string) {
+               var mappings_manager = GamepadMappingsManager.get_instance ();
+               try {
+                       var mapping = new GamepadMapping.from_sdl_string (sdl_string);
+                       gamepad.set_mapping (mapping);
+                       mappings_manager.save_mapping (gamepad.guid, gamepad.name, sdl_string);
+               }
+               catch (Error e) {
+                       warning (e.message);
+               }
+       }
+}


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