[gnome-games/wip/abhinavsingh/gamepad-config] ui: temp patch



commit 793b7b577d316247acaae5624d0f44d76983351c
Author: theawless <theawless gmail com>
Date:   Fri Jul 21 00:34:37 2017 +0530

    ui: temp patch
    
    Add Gamepad Tester, Mapper, Configurer, ViewConfiguration.
    Allow custom header bars in preferences window.
    Improve GamepadView.
    Allow immersive mode in preferences window.
    Fix hat mapping in MappingBuilder.

 data/Makefile.am                         |    3 +
 data/org.gnome.Games.gresource.xml       |    3 +
 data/ui/gamepad-configurer.ui            |  106 +++++++++++++++
 data/ui/gamepad-mapper.ui                |   66 ----------
 data/ui/gamepad-tester.ui                |   18 +++
 data/ui/preferences-page-inputs.ui       |    4 +
 data/ui/preferences-page-plugins.ui      |    4 +
 data/ui/preferences-page-video.ui        |    4 +
 data/ui/preferences-window.ui            |   18 ---
 data/ui/reset-gamepad-mapping-dialog.ui  |   32 +++++
 src/Makefile.am                          |    3 +
 src/gamepad/gamepad-mapping-builder.vala |   15 ++-
 src/ui/gamepad-configurer.vala           |  209 ++++++++++++++++++++++++++++++
 src/ui/gamepad-mapper.vala               |  180 ++++----------------------
 src/ui/gamepad-tester.vala               |   75 +++++++++++
 src/ui/gamepad-view.vala                 |   37 +++---
 src/ui/preferences-page-inputs.vala      |   67 ++++++----
 src/ui/preferences-page-plugins.vala     |   17 +--
 src/ui/preferences-page-video.vala       |   15 +--
 src/ui/preferences-page.vala             |    5 +-
 src/ui/preferences-window.vala           |   87 ++++++++-----
 src/ui/reset-gamepad-mapping-dialog.vala |    5 +
 22 files changed, 632 insertions(+), 341 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index dd8eb44..90c21b6 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -37,7 +37,9 @@ EXTRA_DIST = \
        ui/empty-collection.ui \
        ui/error-display.ui \
        ui/error-info-bar.ui \
+       ui/gamepad-configurer.ui \
        ui/gamepad-mapper.ui \
+       ui/gamepad-tester.ui \
        ui/game-icon-view.ui \
        ui/media-menu-button.ui \
        ui/media-selector.ui \
@@ -48,6 +50,7 @@ EXTRA_DIST = \
        ui/preferences-window.ui \
        ui/quit-dialog.ui \
        ui/remote-display.ui \
+       ui/reset-gamepad-mapping-dialog.ui \
        ui/resume-dialog.ui \
        ui/resume-failed-dialog.ui \
        ui/search-bar.ui \
diff --git a/data/org.gnome.Games.gresource.xml b/data/org.gnome.Games.gresource.xml
index 9e628d9..ed0986a 100644
--- a/data/org.gnome.Games.gresource.xml
+++ b/data/org.gnome.Games.gresource.xml
@@ -16,7 +16,9 @@
     <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-configurer.ui</file>
     <file preprocess="xml-stripblanks">ui/gamepad-mapper.ui</file>
+    <file preprocess="xml-stripblanks">ui/gamepad-tester.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>
@@ -27,6 +29,7 @@
     <file preprocess="xml-stripblanks">ui/preferences-window.ui</file>
     <file preprocess="xml-stripblanks">ui/quit-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/remote-display.ui</file>
+    <file preprocess="xml-stripblanks">ui/reset-gamepad-mapping-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/resume-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/resume-failed-dialog.ui</file>
     <file preprocess="xml-stripblanks">ui/search-bar.ui</file>
diff --git a/data/ui/gamepad-configurer.ui b/data/ui/gamepad-configurer.ui
new file mode 100644
index 0000000..e0767da
--- /dev/null
+++ b/data/ui/gamepad-configurer.ui
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GamesGamepadConfigurer" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkStack" id="stack">
+        <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>
+        <child>
+          <object class="GtkBox" id="gamepad_mapper_holder">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="name">gamepad_mapper</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="gamepad_tester_holder">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+          </object>
+          <packing>
+            <property name="name">gamepad_tester</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkActionBar" id="action_bar">
+        <property name="visible">True</property>
+        <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"/>
+            <style>
+              <class name="destructive-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="configure_button">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Configure</property>
+            <signal name="clicked" handler="on_configure_clicked"/>
+            <style>
+              <class name="suggested-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack-type">start</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkHeaderBar" id="header_bar">
+    <property name="visible">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="cancel_button">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Cancel</property>
+        <signal name="clicked" handler="on_cancel_clicked"/>
+        <style>
+          <class name="destructive-action"/>
+        </style>
+      </object>
+      <packing>
+        <property name="pack-type">end</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/data/ui/gamepad-mapper.ui b/data/ui/gamepad-mapper.ui
index 7b04b28..b38d7bd 100644
--- a/data/ui/gamepad-mapper.ui
+++ b/data/ui/gamepad-mapper.ui
@@ -4,7 +4,6 @@
     <property name="visible">True</property>
     <property name="can_focus">False</property>
     <property name="orientation">vertical</property>
-    <property name="spacing">6</property>
     <child>
       <object class="GtkBox" id="gamepad_view_holder">
         <property name="visible">True</property>
@@ -18,33 +17,6 @@
       <object class="GtkActionBar" id="action_bar">
         <property name="visible">True</property>
         <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">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"/>
-            <style>
-              <class name="destructive-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>
@@ -62,42 +34,4 @@
       </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 type="center">
-      <object class="GtkLabel" id="title">
-        <property name="visible">True</property>
-        <style>
-          <class name="title"/>
-        </style>
-      </object>
-    </child>
-  </object>
 </interface>
diff --git a/data/ui/gamepad-tester.ui b/data/ui/gamepad-tester.ui
new file mode 100644
index 0000000..ab43ea1
--- /dev/null
+++ b/data/ui/gamepad-tester.ui
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GamesGamepadTester" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox" id="gamepad_view_holder">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="halign">fill</property>
+        <property name="valign">fill</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/data/ui/preferences-page-inputs.ui b/data/ui/preferences-page-inputs.ui
index 6df11f0..6cfc237 100644
--- a/data/ui/preferences-page-inputs.ui
+++ b/data/ui/preferences-page-inputs.ui
@@ -64,4 +64,8 @@
       </packing>
     </child>
   </template>
+  <object class="GtkHeaderBar" id="default_header_bar">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">Inputs</property>
+  </object>
 </interface>
diff --git a/data/ui/preferences-page-plugins.ui b/data/ui/preferences-page-plugins.ui
index 75a7615..4b47370 100644
--- a/data/ui/preferences-page-plugins.ui
+++ b/data/ui/preferences-page-plugins.ui
@@ -45,4 +45,8 @@
       </object>
     </child>
   </template>
+  <object class="GtkHeaderBar" id="header_bar">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">Extensions</property>
+  </object>
 </interface>
diff --git a/data/ui/preferences-page-video.ui b/data/ui/preferences-page-video.ui
index 50b473e..e900d7f 100644
--- a/data/ui/preferences-page-video.ui
+++ b/data/ui/preferences-page-video.ui
@@ -50,4 +50,8 @@
       </object>
     </child>
   </template>
+  <object class="GtkHeaderBar" id="header_bar">
+    <property name="visible">True</property>
+    <property name="title" translatable="yes">Video</property>
+  </object>
 </interface>
diff --git a/data/ui/preferences-window.ui b/data/ui/preferences-window.ui
index 2e54d0b..10d6251 100644
--- a/data/ui/preferences-window.ui
+++ b/data/ui/preferences-window.ui
@@ -28,24 +28,6 @@
             <property name="visible">True</property>
           </object>
         </child>
-        <child>
-          <object class="GtkHeaderBar" id="right_header_bar">
-            <property name="name">right_header_bar</property>
-            <property name="visible">True</property>
-            <property name="expand">True</property>
-            <property name="show-close-button">True</property>
-            <property name="decoration_layout">:close</property>
-            <child>
-              <object class="GtkStack" id="controls_stack">
-                <property name="homogeneous">false</property>
-                <property name="visible">true</property>
-              </object>
-              <packing>
-                <property name="pack-type">start</property>
-              </packing>
-            </child>
-          </object>
-        </child>
       </object>
     </child>
     <child>
diff --git a/data/ui/reset-gamepad-mapping-dialog.ui b/data/ui/reset-gamepad-mapping-dialog.ui
new file mode 100644
index 0000000..146c0b4
--- /dev/null
+++ b/data/ui/reset-gamepad-mapping-dialog.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.16"/>
+  <template class="GamesResetGamepadMappingDialog" parent="GtkMessageDialog">
+    <property name="modal">True</property>
+    <property name="destroy-with-parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="message_type">question</property>
+    <property name="text" translatable="yes">Factory reset mapping for this gamepad?</property>
+    <property name="secondary_text" translatable="yes">Your mapping will be lost.</property>
+    <child type="action">
+      <object class="GtkButton" id="button_cancel">
+        <property name="visible">True</property>
+        <property name="can-default">True</property>
+        <property name="label" translatable="yes">Cancel</property>
+      </object>
+    </child>
+    <child type="action">
+      <object class="GtkButton" id="button_reset">
+        <property name="visible">True</property>
+        <property name="label" translatable="yes">Reset</property>
+        <style>
+          <class name="destructive-action"/>
+        </style>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="accept">button_reset</action-widget>
+      <action-widget response="cancel" default="true">button_cancel</action-widget>
+    </action-widgets>
+  </template>
+</interface>
diff --git a/src/Makefile.am b/src/Makefile.am
index d6c5ffc..c19e07e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -146,7 +146,9 @@ gnome_games_SOURCES = \
        ui/empty-collection.vala \
        ui/error-display.vala \
        ui/error-info-bar.vala \
+       ui/gamepad-configurer.vala \
        ui/gamepad-mapper.vala \
+       ui/gamepad-tester.vala \
        ui/gamepad-view.vala \
        ui/game-icon-view.vala \
        ui/game-thumbnail.vala \
@@ -161,6 +163,7 @@ gnome_games_SOURCES = \
        ui/preferences-window.vala \
        ui/quit-dialog.vala \
        ui/remote-display.vala \
+       ui/reset-gamepad-mapping-dialog.vala \
        ui/resume-dialog.vala \
        ui/resume-failed-dialog.vala \
        ui/search-bar.vala \
diff --git a/src/gamepad/gamepad-mapping-builder.vala b/src/gamepad/gamepad-mapping-builder.vala
index ee8678f..9565e5a 100644
--- a/src/gamepad/gamepad-mapping-builder.vala
+++ b/src/gamepad/gamepad-mapping-builder.vala
@@ -64,18 +64,21 @@ private class Games.GamepadMappingBuilder : Object {
                return add_destination (destination_string, source);
        }
 
-       public bool set_hat_mapping (uint8 hardware_index, int32 hardware_value, uint16 axis, GamepadInput 
source) {
-               var destination_string = "h" + hardware_index.to_string ();
+       public bool set_hat_mapping (uint8 hardware_index, int32 value, GamepadInput source) {
+               var dpad_index = hardware_index / 2;
+               var dpad_axis = hardware_index % 2;
+
+               var destination_string = "h" + dpad_index.to_string ();
                destination_string += ".";
 
                while (dpads.length <= hardware_index)
                        dpads += GamepadDPad ();
-               var dpad = dpads[hardware_index];
-               var changed_value = hardware_value == 0 ? dpad.axis_values[axis] : hardware_value;
-               dpad.axis_values[axis] = hardware_value;
+               var dpad = dpads[dpad_index];
+               var changed_value = value == 0 ? dpad.axis_values[dpad_axis] : value;
+               dpad.axis_values[dpad_axis] = value;
 
                // add 4 so the remainder is positive
-               var dpad_position = (changed_value + axis + 4) % 4;
+               var dpad_position = (changed_value + dpad_axis + 4) % 4;
                var dpad_position_2pow = Math.pow (2, dpad_position);
                destination_string += dpad_position_2pow.to_string ();
 
diff --git a/src/ui/gamepad-configurer.vala b/src/ui/gamepad-configurer.vala
new file mode 100644
index 0000000..2c075ae
--- /dev/null
+++ b/src/ui/gamepad-configurer.vala
@@ -0,0 +1,209 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/gamepad-configurer.ui")]
+private class Games.GamepadConfigurer : Gtk.Box {
+
+       private const GamepadInput[] STANDARD_GAMEPAD_INPUTS = {
+               { EventCode.EV_KEY, EventCode.BTN_A },
+               { EventCode.EV_KEY, EventCode.BTN_B },
+               { EventCode.EV_KEY, EventCode.BTN_X },
+               { EventCode.EV_KEY, EventCode.BTN_Y },
+               { EventCode.EV_KEY, EventCode.BTN_THUMBL },
+               { EventCode.EV_KEY, EventCode.BTN_THUMBR },
+               { EventCode.EV_KEY, EventCode.BTN_TL },
+               { EventCode.EV_KEY, EventCode.BTN_TR },
+               { EventCode.EV_KEY, EventCode.BTN_TL2 },
+               { EventCode.EV_KEY, EventCode.BTN_TR2 },
+               { EventCode.EV_KEY, EventCode.BTN_DPAD_UP },
+               { EventCode.EV_KEY, EventCode.BTN_DPAD_LEFT },
+               { EventCode.EV_KEY, EventCode.BTN_DPAD_DOWN },
+               { EventCode.EV_KEY, EventCode.BTN_DPAD_RIGHT },
+               { EventCode.EV_KEY, EventCode.BTN_SELECT },
+               { EventCode.EV_KEY, EventCode.BTN_MODE },
+               { EventCode.EV_KEY, EventCode.BTN_START },
+               { EventCode.EV_ABS, EventCode.ABS_X },
+               { EventCode.EV_ABS, EventCode.ABS_RX },
+               { EventCode.EV_ABS, EventCode.ABS_Y },
+               { EventCode.EV_ABS, EventCode.ABS_RY },
+       };
+
+       private const GamepadInputPath[] STANDARD_GAMEPAD_INPUT_PATHS = {
+               { { EventCode.EV_ABS, EventCode.ABS_X }, "leftx" },
+               { { EventCode.EV_ABS, EventCode.ABS_Y }, "lefty" },
+               { { EventCode.EV_ABS, EventCode.ABS_RX }, "rightx" },
+               { { EventCode.EV_ABS, EventCode.ABS_RY }, "righty" },
+               { { EventCode.EV_KEY, EventCode.BTN_A }, "a" },
+               { { EventCode.EV_KEY, EventCode.BTN_B }, "b" },
+               { { EventCode.EV_KEY, EventCode.BTN_DPAD_DOWN }, "dpdown" },
+               { { EventCode.EV_KEY, EventCode.BTN_DPAD_LEFT }, "dpleft" },
+               { { EventCode.EV_KEY, EventCode.BTN_DPAD_RIGHT }, "dpright" },
+               { { EventCode.EV_KEY, EventCode.BTN_DPAD_UP }, "dpup" },
+               { { EventCode.EV_KEY, EventCode.BTN_MODE }, "guide" },
+               { { EventCode.EV_KEY, EventCode.BTN_SELECT }, "back" },
+               { { EventCode.EV_KEY, EventCode.BTN_TL }, "leftshoulder" },
+               { { EventCode.EV_KEY, EventCode.BTN_TR }, "rightshoulder" },
+               { { EventCode.EV_KEY, EventCode.BTN_START }, "start" },
+               { { EventCode.EV_KEY, EventCode.BTN_THUMBL }, "leftstick" },
+               { { EventCode.EV_KEY, EventCode.BTN_THUMBR }, "rightstick" },
+               { { EventCode.EV_KEY, EventCode.BTN_TL2 }, "lefttrigger" },
+               { { EventCode.EV_KEY, EventCode.BTN_TR2 }, "righttrigger" },
+               { { EventCode.EV_KEY, EventCode.BTN_Y }, "x" },
+               { { EventCode.EV_KEY, EventCode.BTN_X }, "y" },
+       };
+
+       private const GamepadViewConfiguration STANDARD_GAMEPAD_VIEW_CONFIGURATION = {
+               "resource:///org/gnome/Games/gamepads/standard-gamepad.svg", STANDARD_GAMEPAD_INPUT_PATHS
+       };
+
+       private enum State {
+               TEST,
+               CONFIGURE,
+       }
+
+       public signal void back ();
+
+       private State? _state;
+       private State? state {
+               set {
+                       _state = value;
+                       immersive_mode = (state == State.CONFIGURE);
+
+                       switch (value) {
+                       case State.TEST:
+                               action_bar.show ();
+                               back_button.show ();
+                               cancel_button.hide ();
+                               header_bar.title = _("Testing ") + gamepad.name;
+                               header_bar.get_style_context ().remove_class ("selection-mode");
+                               stack.set_visible_child_name ("gamepad_tester");
+
+                               tester.start ();
+                               mapper.stop ();
+                               mapper.finished.disconnect (save_mapping);
+
+                               break;
+                       case State.CONFIGURE:
+                               action_bar.hide ();
+                               back_button.hide ();
+                               cancel_button.show ();
+                               header_bar.title = _("Configuring ") + gamepad.name;
+                               header_bar.get_style_context ().add_class ("selection-mode");
+                               stack.set_visible_child_name ("gamepad_mapper");
+
+                               tester.stop ();
+                               mapper.start ();
+                               mapper.finished.connect (save_mapping);
+
+                               break;
+                       }
+               }
+               get { return _state; }
+       }
+
+       [GtkChild (name = "header_bar")]
+       private Gtk.HeaderBar _header_bar;
+       public Gtk.HeaderBar header_bar {
+               private set { _header_bar = value; }
+               get { return _header_bar; }
+       }
+
+       private bool _immersive_mode;
+       public bool immersive_mode { 
+               private set { _immersive_mode = value; }
+               get { return _immersive_mode; }
+       }
+
+       [GtkChild]
+       private Gtk.Stack stack;
+       [GtkChild]
+       private Gtk.Box gamepad_mapper_holder;
+       [GtkChild]
+       private Gtk.Box gamepad_tester_holder;
+       [GtkChild]
+       private Gtk.ActionBar action_bar;
+       [GtkChild]
+       private Gtk.Button reset_button;
+       [GtkChild]
+       private Gtk.Button configure_button;
+       [GtkChild]
+       private Gtk.Button back_button;
+       [GtkChild]
+       private Gtk.Button cancel_button;
+
+       private Gamepad gamepad;
+       private GamepadMapper mapper;
+       private GamepadTester tester;
+
+       public GamepadConfigurer (Gamepad gamepad) {
+               this.gamepad = gamepad;
+               mapper = new GamepadMapper (gamepad, STANDARD_GAMEPAD_VIEW_CONFIGURATION, 
STANDARD_GAMEPAD_INPUTS);
+               gamepad_mapper_holder.pack_start (mapper);
+               tester = new GamepadTester (gamepad, STANDARD_GAMEPAD_VIEW_CONFIGURATION);
+               gamepad_tester_holder.pack_start (tester);
+
+               state = State.TEST;
+       }
+
+       [GtkCallback]
+       private void on_reset_clicked () {
+               reset_mapping ();
+       }
+
+       [GtkCallback]
+       private void on_configure_clicked () {
+               state = State.CONFIGURE;
+       }
+
+       [GtkCallback]
+       private void on_back_clicked () {
+               back ();
+       }
+
+       [GtkCallback]
+       private void on_cancel_clicked () {
+               state = State.TEST;
+       }
+
+       private void on_mapper_finished (string sdl_string) {
+               state = State.TEST;
+               save_sdl_string (sdl_string);
+       }
+
+       private void reset_mapping () {
+               var message_dialog = new ResetGamepadMappingDialog ();
+               message_dialog.set_transient_for ((Gtk.Window) get_toplevel ());
+               message_dialog.response.connect ((response) => {
+                       switch (response) {
+                               case Gtk.ResponseType.ACCEPT:
+                                       var mappings_manager = GamepadMappingsManager.get_instance ();
+                                       var sdl_string =  mappings_manager.get_default_mapping (gamepad.guid);
+                                       if (sdl_string != null)
+                                               save_sdl_string (sdl_string);
+
+                                       break;
+                               default:
+                                       break;
+                       }
+
+                       message_dialog.destroy();
+               });
+               message_dialog.show ();
+       }
+
+       private void save_mapping (string sdl_string) {
+               state = State.TEST;
+               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);
+               }
+       }
+}
diff --git a/src/ui/gamepad-mapper.vala b/src/ui/gamepad-mapper.vala
index 5983e81..1e63d5f 100644
--- a/src/ui/gamepad-mapper.vala
+++ b/src/ui/gamepad-mapper.vala
@@ -2,53 +2,12 @@
 
 [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 {
-                       switch (value) {
-                       case State.BEGIN:
-                               apply_button.set_sensitive (false);
-                               title.label = _("Configuring ") + gamepad.name;
-                               connect_to_gamepad ();
-
-                               break;
-                       case State.CONFIGURE:
-                               gamepad_view.reset ();
-                               gamepad_view.highlight (input, true);
-
-                               break;
-                       case State.FINISH:
-                               gamepad_view.reset ();
-                               skip_button.set_sensitive (false);
-                               apply_button.set_sensitive (true);
-                               title.label = _("Finished configuration");
-                               disconnect_from_gamepad ();
-
-                               break;
-                       }
-
-                       _state = value;
-               }
-               get { return _state; }
-       }
+       public signal void finished (string sdl_string);
 
        private GamepadInput? _input;
        private GamepadInput? input {
                set {
                        _input = value;
-                       if (_input == null) {
-                               info_message.label = "";
-
-                               return;
-                       }
 
                        switch (input.type) {
                        case EventCode.EV_KEY:
@@ -70,95 +29,37 @@ private class Games.GamepadMapper : Gtk.Box {
        }
 
        [GtkChild]
-       public Gtk.Box header_content;
-       [GtkChild]
-       private Gtk.Button apply_button;
-       [GtkChild]
-       private Gtk.Button skip_button;
-       [GtkChild]
        private Gtk.Box gamepad_view_holder;
        [GtkChild]
-       private Gtk.Label title;
-       [GtkChild]
        private Gtk.Label info_message;
 
-       private const GamepadInput[] STANDARD_GAMEPAD_INPUTS = {
-               { EventCode.EV_KEY, EventCode.BTN_A },
-               { EventCode.EV_KEY, EventCode.BTN_B },
-               { EventCode.EV_KEY, EventCode.BTN_X },
-               { EventCode.EV_KEY, EventCode.BTN_Y },
-               { EventCode.EV_KEY, EventCode.BTN_THUMBL },
-               { EventCode.EV_KEY, EventCode.BTN_THUMBR },
-               { EventCode.EV_KEY, EventCode.BTN_TL },
-               { EventCode.EV_KEY, EventCode.BTN_TR },
-               { EventCode.EV_KEY, EventCode.BTN_TL2 },
-               { EventCode.EV_KEY, EventCode.BTN_TR2 },
-               { EventCode.EV_KEY, EventCode.BTN_DPAD_UP },
-               { EventCode.EV_KEY, EventCode.BTN_DPAD_LEFT },
-               { EventCode.EV_KEY, EventCode.BTN_DPAD_DOWN },
-               { EventCode.EV_KEY, EventCode.BTN_DPAD_RIGHT },
-               { EventCode.EV_KEY, EventCode.BTN_SELECT },
-               { EventCode.EV_KEY, EventCode.BTN_MODE },
-               { EventCode.EV_KEY, EventCode.BTN_START },
-               { EventCode.EV_ABS, EventCode.ABS_X },
-               { EventCode.EV_ABS, EventCode.ABS_RX },
-               { EventCode.EV_ABS, EventCode.ABS_Y },
-               { EventCode.EV_ABS, EventCode.ABS_RY },
-       };
-
-       private const GamepadInputPath[] STANDARD_GAMEPAD_INPUT_PATHS = {
-               { { EventCode.EV_ABS, EventCode.ABS_X }, "leftx" },
-               { { EventCode.EV_ABS, EventCode.ABS_Y }, "lefty" },
-               { { EventCode.EV_ABS, EventCode.ABS_RX }, "rightx" },
-               { { EventCode.EV_ABS, EventCode.ABS_RY }, "righty" },
-               { { EventCode.EV_KEY, EventCode.BTN_A }, "a" },
-               { { EventCode.EV_KEY, EventCode.BTN_B }, "b" },
-               { { EventCode.EV_KEY, EventCode.BTN_DPAD_DOWN }, "dpdown" },
-               { { EventCode.EV_KEY, EventCode.BTN_DPAD_LEFT }, "dpleft" },
-               { { EventCode.EV_KEY, EventCode.BTN_DPAD_RIGHT }, "dpright" },
-               { { EventCode.EV_KEY, EventCode.BTN_DPAD_UP }, "dpup" },
-               { { EventCode.EV_KEY, EventCode.BTN_MODE }, "guide" },
-               { { EventCode.EV_KEY, EventCode.BTN_SELECT }, "back" },
-               { { EventCode.EV_KEY, EventCode.BTN_TL }, "leftshoulder" },
-               { { EventCode.EV_KEY, EventCode.BTN_TR }, "rightshoulder" },
-               { { EventCode.EV_KEY, EventCode.BTN_START }, "start" },
-               { { EventCode.EV_KEY, EventCode.BTN_THUMBL }, "leftstick" },
-               { { EventCode.EV_KEY, EventCode.BTN_THUMBR }, "rightstick" },
-               { { EventCode.EV_KEY, EventCode.BTN_TL2 }, "lefttrigger" },
-               { { EventCode.EV_KEY, EventCode.BTN_TR2 }, "righttrigger" },
-               { { EventCode.EV_KEY, EventCode.BTN_Y }, "x" },
-               { { EventCode.EV_KEY, EventCode.BTN_X }, "y" },
-       };
-
-       private const GamepadViewConfiguration STANDARD_GAMEPAD_VIEW_CONFIGURATION = {
-               "resource:///org/gnome/Games/gamepads/standard-gamepad.svg", STANDARD_GAMEPAD_INPUT_PATHS
-       };
-
        private Gamepad gamepad;
        private GamepadView gamepad_view;
        private GamepadMappingBuilder mapping_builder;
-       private ulong gamepad_event_handler_id;
+       private GamepadInput[] mapping_inputs;
        private uint current_input_index;
 
-       public GamepadMapper (Gamepad gamepad) {
+       private ulong gamepad_event_handler_id;
+
+       public GamepadMapper (Gamepad gamepad, GamepadViewConfiguration configuration, GamepadInput[] 
mapping_inputs) {
                this.gamepad = gamepad;
-               mapping_builder = new GamepadMappingBuilder ();
-               state = State.BEGIN;
-               current_input_index = 0;
+               this.mapping_inputs = mapping_inputs;
 
-               gamepad_view = new GamepadView (STANDARD_GAMEPAD_VIEW_CONFIGURATION);
+               gamepad_view = new GamepadView (configuration);
                gamepad_view_holder.pack_start (gamepad_view);
                gamepad_view.show ();
        }
 
        public void start () {
+               mapping_builder = new GamepadMappingBuilder ();
+               current_input_index = 0;
+               connect_to_gamepad ();
+
                next_input ();
        }
 
-       [GtkCallback]
-       private void on_apply_clicked () {
-               save_mapping ();
-               back ();
+       public void stop () {
+               disconnect_from_gamepad ();
        }
 
        [GtkCallback]
@@ -166,19 +67,8 @@ private class Games.GamepadMapper : Gtk.Box {
                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) => {
+               gamepad_event_handler_id = gamepad.event.connect ((event) => {
                        switch (event.type) {
                        case EventType.EVENT_GAMEPAD_BUTTON_RELEASE:
                                on_button_event (event.gamepad_button);
@@ -199,7 +89,10 @@ private class Games.GamepadMapper : Gtk.Box {
        }
 
        private void disconnect_from_gamepad () {
-               gamepad.disconnect (gamepad_event_handler_id);
+               if (gamepad_event_handler_id != 0) {
+                       gamepad.disconnect (gamepad_event_handler_id);
+                       gamepad_event_handler_id = 0;
+               }
        }
 
        private void on_button_event (EventGamepadButton event) {
@@ -235,7 +128,6 @@ private class Games.GamepadMapper : Gtk.Box {
 
                var success = mapping_builder.set_hat_mapping (event.gamepad_hat.hardware_index,
                                                               event.gamepad_hat.value,
-                                                              event.gamepad_hat.axis,
                                                               input);
                if (!success)
                        return;
@@ -244,39 +136,15 @@ private class Games.GamepadMapper : Gtk.Box {
        }
 
        private void next_input () {
-               if (state == State.FINISH)
-                       return;
-               if (current_input_index >= STANDARD_GAMEPAD_INPUTS.length) {
-                       input = null;
-                       state = State.FINISH;
+               if (current_input_index == mapping_inputs.length) {
+                       var sdl_string = mapping_builder.build_sdl_string ();
+                       finished (sdl_string);
 
                        return;
                }
 
-               input = STANDARD_GAMEPAD_INPUTS[current_input_index++];
-               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);
-               }
+               gamepad_view.reset ();
+               input = mapping_inputs[current_input_index++];
+               gamepad_view.highlight (input, true);
        }
 }
diff --git a/src/ui/gamepad-tester.vala b/src/ui/gamepad-tester.vala
new file mode 100644
index 0000000..509cc59
--- /dev/null
+++ b/src/ui/gamepad-tester.vala
@@ -0,0 +1,75 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/gamepad-tester.ui")]
+private class Games.GamepadTester : Gtk.Box {
+       [GtkChild]
+       private Gtk.Box gamepad_view_holder;
+
+       private Gamepad gamepad;
+       private GamepadView gamepad_view;
+       private GamepadInput current_input; 
+
+       private ulong gamepad_button_event_handler_id;
+       private ulong gamepad_axis_event_handler_id;
+       private ulong gamepad_hat_event_handler_id;
+       private uint gamepad_view_unhighlight_id;
+
+       public GamepadTester (Gamepad gamepad, GamepadViewConfiguration configuration) {
+               this.gamepad = gamepad;
+
+               gamepad_view = new GamepadView (configuration);
+               gamepad_view_holder.pack_start (gamepad_view);
+               gamepad_view.show ();
+       }
+
+       public void start () {
+               connect_to_gamepad ();
+       }
+
+       public void stop () {
+               disconnect_from_gamepad ();
+       }
+
+       private void connect_to_gamepad () {
+               gamepad_button_event_handler_id = gamepad.button_press_event.connect ((event) => {
+                       highlight_input (EventCode.EV_KEY, event.gamepad_button.button);
+               });
+               gamepad_axis_event_handler_id = gamepad.axis_event.connect ((event) => {
+                       if (!(-0.8 < event.gamepad_axis.value && event.gamepad_axis.value < 0.8))
+                               highlight_input (EventCode.EV_ABS, event.gamepad_axis.axis);
+               });
+               gamepad_button_event_handler_id = gamepad.hat_event.connect ((event) => {
+                       if (event.gamepad_hat.value != 0)
+                               highlight_input (EventCode.EV_ABS, event.gamepad_hat.axis);
+               });
+       }
+
+       private void disconnect_from_gamepad () {
+               if (gamepad_button_event_handler_id != 0) {
+                       gamepad.disconnect (gamepad_button_event_handler_id);
+                       gamepad_button_event_handler_id = 0;
+               }
+               if (gamepad_axis_event_handler_id != 0) {
+                       gamepad.disconnect (gamepad_axis_event_handler_id);
+                       gamepad_axis_event_handler_id = 0;
+               }
+               if (gamepad_hat_event_handler_id != 0) {
+                       gamepad.disconnect (gamepad_hat_event_handler_id);
+                       gamepad_axis_event_handler_id = 0;
+               }
+       }
+
+       private void highlight_input (uint16 type, uint16 code) {
+               if (gamepad_button_event_handler_id != 0)
+                       gamepad_view.highlight (current_input, false);
+
+               current_input = {type, code};
+               gamepad_view.highlight (current_input, true);
+               gamepad_view_unhighlight_id = Timeout.add (200, () => {
+                       gamepad_view.highlight (current_input, false);
+                       gamepad_view_unhighlight_id = 0;
+
+                       return false;
+               });
+       }
+}
diff --git a/src/ui/gamepad-view.vala b/src/ui/gamepad-view.vala
index 1399186..fb71505 100644
--- a/src/ui/gamepad-view.vala
+++ b/src/ui/gamepad-view.vala
@@ -27,29 +27,33 @@ private class Games.GamepadView : Gtk.DrawingArea {
                queue_draw ();
        }
 
-       public void highlight (GamepadInput input, bool highlight) {
-               for (var i = 0; i < configuration.input_paths.length; ++i)
-                       if (configuration.input_paths[i].input == input)
+       public bool highlight (GamepadInput input, bool highlight) {
+               for (var i = 0; i < configuration.input_paths.length; ++i) {
+                       if (configuration.input_paths[i].input == input) {
                                input_highlights[i] = highlight;
+                               queue_draw ();
 
-               queue_draw ();
+                               return true;
+                       }
+               }
+
+               return false;
        }
 
        public override bool draw (Cairo.Context context) {
                double x, y, scale;
                calculate_image_dimensions (out x, out y, out scale);
 
-               color_gamepad (context, x, y, scale);
-               highlight_gamepad (context, x, y, scale);
+               var color_context = create_similar_context (context, x, y, scale);
+               color_gamepad (context, color_context);
+               var highlight_context = create_similar_context (context, x, y, scale);
+               highlight_gamepad (context, highlight_context);
 
                return false;
        }
 
-       private void color_gamepad (Cairo.Context gamepad_context, double x, double y, double scale) {
-               var color_context = create_similar_context (gamepad_context);
+       private void color_gamepad (Cairo.Context gamepad_context, Cairo.Context color_context) {
                var color_suface = color_context.get_target ();
-               color_context.translate (x, y);
-               color_context.scale (scale, scale);
 
                handle.render_cairo (color_context);
 
@@ -58,11 +62,8 @@ private class Games.GamepadView : Gtk.DrawingArea {
                gamepad_context.mask_surface (color_suface, 0, 0);
        }
 
-       private void highlight_gamepad (Cairo.Context gamepad_context, double x, double y, double scale) {
-               var highlight_context = create_similar_context (gamepad_context);
+       private void highlight_gamepad (Cairo.Context gamepad_context, Cairo.Context highlight_context) {
                var highlight_suface = highlight_context.get_target ();
-               highlight_context.translate (x, y);
-               highlight_context.scale (scale, scale);
                
                for (var i = 0; i < configuration.input_paths.length; ++i)
                        if (input_highlights[i])
@@ -73,12 +74,16 @@ private class Games.GamepadView : Gtk.DrawingArea {
                gamepad_context.mask_surface (highlight_suface, 0, 0);
        }
 
-       private Cairo.Context create_similar_context (Cairo.Context context) {
+       private Cairo.Context create_similar_context (Cairo.Context context, double x, double y, double 
scale) {
                var w = get_allocated_width ();
                var h = get_allocated_height ();
                var surface = context.get_target ();
                var similar_suface = new Cairo.Surface.similar (surface, Cairo.Content.COLOR_ALPHA, w, h);
-               return new Cairo.Context (similar_suface);
+               var similar_context = new Cairo.Context (similar_suface);
+               similar_context.translate (x, y);
+               similar_context.scale (scale, scale);
+
+               return similar_context;
        }
 
        private void calculate_image_dimensions (out double x, out double y, out double scale) {
diff --git a/src/ui/preferences-page-inputs.vala b/src/ui/preferences-page-inputs.vala
index 59b925a..ee83f6a 100644
--- a/src/ui/preferences-page-inputs.vala
+++ b/src/ui/preferences-page-inputs.vala
@@ -2,41 +2,42 @@
 
 [GtkTemplate (ui = "/org/gnome/Games/ui/preferences-page-inputs.ui")]
 private class Games.PreferencesPageInputs: Gtk.Stack, PreferencesPage {
-       private Gtk.Widget? _custom_title;
-       public Gtk.Widget? custom_title {
-               get { return _custom_title; }
-               protected set { _custom_title = value; }
-       }
-       
-       public string? subtitle {
-               get { return null; }
-               protected set {}
+       private Gtk.HeaderBar _header_bar;
+       public Gtk.HeaderBar header_bar {
+               protected set { _header_bar = value; }
+               get { return _header_bar; }
        }
 
-       private string? _title;
-       public string? title {
-               get { return _title; }
-               protected set { _title = value; }
-       }
+       private bool _immersive_mode;
+       public bool immersive_mode {
+               protected set { _immersive_mode = value; }
+               get { return _immersive_mode; }
+       }
 
        [GtkChild]
        private Gtk.ListBox gamepads_list_box;
        [GtkChild]
        private Gtk.Box extra_stack_child_holder;
+       [GtkChild]
+       private Gtk.HeaderBar default_header_bar;
+
        private GamepadMonitor gamepad_monitor;
-       private Gtk.Label default_label;
+       private Binding header_bar_binding;
+       private Binding immersive_mode_binding;
+       private ulong back_handler_id;
 
        construct {
-               title = _("Inputs");
-               gamepad_monitor = GamepadMonitor.get_instance ();
+               header_bar = default_header_bar;
+               immersive_mode = false;
 
+               gamepad_monitor = GamepadMonitor.get_instance ();
                gamepad_monitor.gamepad_unplugged.connect (rebuild_gamepad_list);
                gamepad_monitor.gamepad_plugged.connect (rebuild_gamepad_list);
                build_gamepad_list ();
        }
 
        public void visible_page_changed () {
-               on_mapper_back ();
+               on_back (null);
        }
 
        private void rebuild_gamepad_list () {
@@ -72,16 +73,32 @@ private class Games.PreferencesPageInputs: Gtk.Stack, PreferencesPage {
 
                if (gamepad == null)
                        return;
-               var mapper = new GamepadMapper(gamepad);
-               mapper.back.connect (on_mapper_back);
-               custom_title = mapper.header_content;
-               extra_stack_child_holder.pack_start (mapper);
+               var configurer = new GamepadConfigurer(gamepad);
+               back_handler_id = configurer.back.connect (on_back);
+               header_bar_binding = configurer.bind_property ("header-bar", this, "header-bar",
+                                                              BindingFlags.SYNC_CREATE);
+               immersive_mode_binding = configurer.bind_property ("immersive-mode", this, "immersive-mode",
+                                                              BindingFlags.SYNC_CREATE);
+               extra_stack_child_holder.pack_start (configurer);
                set_visible_child_name ("extra_stack_child");
-               mapper.start ();
        }
 
-       private void on_mapper_back () {
-               custom_title = null;
+       private void on_back (Object? emitter) {
+               if (back_handler_id != 0) {
+                       if (emitter != null)
+                               emitter.disconnect (back_handler_id);
+                       back_handler_id = 0;
+               }
+               if (header_bar_binding != null) {
+                       header_bar_binding.unbind ();
+                       header_bar_binding = null;
+               }
+               if (immersive_mode_binding != null) {
+                       immersive_mode_binding.unbind ();
+                       immersive_mode_binding = null;
+               }
+               header_bar = default_header_bar;
+               immersive_mode = false;
                set_visible_child_name ("main_stack_child");
                extra_stack_child_holder.foreach ((child) => child.destroy ());
        }
diff --git a/src/ui/preferences-page-plugins.vala b/src/ui/preferences-page-plugins.vala
index ab85970..a64f55d 100644
--- a/src/ui/preferences-page-plugins.vala
+++ b/src/ui/preferences-page-plugins.vala
@@ -2,19 +2,16 @@
 
 [GtkTemplate (ui = "/org/gnome/Games/ui/preferences-page-plugins.ui")]
 private class Games.PreferencesPagePlugins: Gtk.Bin, PreferencesPage {
-       public Gtk.Widget? custom_title {
-               get { return null; }
+       [GtkChild (name = "header_bar")]
+       private Gtk.HeaderBar _header_bar;
+       public Gtk.HeaderBar header_bar {
                protected set {}
+               get { return _header_bar; }
        }
-       
-       public string? subtitle {
-               get { return null; }
-               protected set {}
-       }
-       
-       public string? title {
-               get { return _("Extensions"); }
+
+       public bool immersive_mode {
                protected set {}
+               get { return false; }
        }
 
        [GtkChild]
diff --git a/src/ui/preferences-page-video.vala b/src/ui/preferences-page-video.vala
index 0829031..b1dca80 100644
--- a/src/ui/preferences-page-video.vala
+++ b/src/ui/preferences-page-video.vala
@@ -2,19 +2,16 @@
 
 [GtkTemplate (ui = "/org/gnome/Games/ui/preferences-page-video.ui")]
 private class Games.PreferencesPageVideo: Gtk.Bin, PreferencesPage {
-       public Gtk.Widget? custom_title {
-               get { return null; }
+       [GtkChild (name = "header_bar")]
+       private Gtk.HeaderBar _header_bar;
+       public Gtk.HeaderBar header_bar {
                protected set {}
+               get { return _header_bar; }
        }
        
-       public string? subtitle {
-               get { return null; }
-               protected set {}
-       }
-       
-       public string? title {
-               get { return _("Video"); }
+       public bool immersive_mode {
                protected set {}
+               get { return false; }
        }
 
        private string _filter_active;
diff --git a/src/ui/preferences-page.vala b/src/ui/preferences-page.vala
index b3d8445..bd8576f 100644
--- a/src/ui/preferences-page.vala
+++ b/src/ui/preferences-page.vala
@@ -1,8 +1,7 @@
 // This file is part of GNOME Games. License: GPL-3.0+.
 
 private interface Games.PreferencesPage: Gtk.Widget {
-       public abstract Gtk.Widget? custom_title { set; protected get; }
-       public abstract string? subtitle { set; protected get; }
-       public abstract string? title { set; protected get; }
+       public abstract Gtk.HeaderBar header_bar { protected set; get; }
+       public abstract bool immersive_mode { protected set; get; }
        public virtual void visible_page_changed () {}
 }
diff --git a/src/ui/preferences-window.vala b/src/ui/preferences-window.vala
index 2ee0aa8..612c2dd 100644
--- a/src/ui/preferences-window.vala
+++ b/src/ui/preferences-window.vala
@@ -3,54 +3,77 @@
 [GtkTemplate (ui = "/org/gnome/Games/ui/preferences-window.ui")]
 private class Games.PreferencesWindow : Gtk.Window {
        [GtkChild]
-       private Gtk.HeaderBar right_header_bar;
+       private Gtk.Box titlebar_box;
+       [GtkChild]
+       private Gtk.HeaderBar left_header_bar;
+       [GtkChild]
+       private Gtk.Separator header_separator;
+       [GtkChild]
+       private Gtk.Box sidebar_vbox;
+       [GtkChild]
+       private Gtk.Separator separator1;
        [GtkChild]
        private Gtk.Stack stack;
 
-       Binding right_header_bar_custom_title_binding;
-       Binding right_header_bar_subtitle_binding;
-       Binding right_header_bar_title_binding;
+       private Gtk.HeaderBar _right_header_bar;
+       public Gtk.HeaderBar right_header_bar {
+               set {
+                       if (_right_header_bar != null)
+                               titlebar_box.remove (_right_header_bar);
+                       if (value != null)
+                               titlebar_box.pack_end (value);
+
+                       _right_header_bar = value;
+               }
+               get { return _right_header_bar; }
+       }
+
+       private bool _immersive_mode;
+       public bool immersive_mode {
+               set {
+                       header_separator.visible = !value;
+                       left_header_bar.visible = !value;
+                       separator1.visible = !value;
+                       sidebar_vbox.visible = !value;
+                       if (right_header_bar != null)
+                               right_header_bar.show_close_button = !value;
+
+                       _immersive_mode = value;
+               }
+               get { return _immersive_mode; }
+       }
+
+       private Binding right_header_bar_binding;
+       private Binding immersive_mode_binding;
 
        public PreferencesWindow () {
                stack.foreach ((child) => {
                        var page = (PreferencesPage) child;
                        stack.notify["visible-child-name"].connect (page.visible_page_changed);
                });
-               stack.notify["visible-child-name"].connect (update_right_header);
-               update_right_header ();
+               stack.notify["visible-child-name"].connect (visible_child_changed);
+               visible_child_changed ();
        }
 
-       private void update_right_header () {
-               reset_right_header_bindings ();
+       private void visible_child_changed () {
+               if (right_header_bar_binding != null) {
+                       right_header_bar_binding.unbind ();
+                       right_header_bar_binding = null;
+               }
+               if (immersive_mode_binding != null) {
+                       immersive_mode_binding.unbind ();
+                       immersive_mode_binding = null;
+               }
 
                var page = (PreferencesPage) stack.get_visible_child ();
                if (page == null) {
-                       right_header_bar.custom_title = null;
-                       right_header_bar.subtitle = null;
-                       right_header_bar.title = null;
+                       right_header_bar = null;
 
                        return;
                }
-               right_header_bar_custom_title_binding = page.bind_property ("custom-title", right_header_bar, 
"custom-title",
-                                                                           BindingFlags.SYNC_CREATE);
-               right_header_bar_subtitle_binding = page.bind_property ("subtitle", right_header_bar, 
"subtitle",
-                                                                       BindingFlags.SYNC_CREATE);
-               right_header_bar_title_binding = page.bind_property ("title", right_header_bar, "title",
-                                                                    BindingFlags.SYNC_CREATE);
-       }
-
-       private void reset_right_header_bindings () {
-               if (right_header_bar_custom_title_binding != null) {
-                       right_header_bar_custom_title_binding.unbind ();
-                       right_header_bar_custom_title_binding = null;
-               }
-               if (right_header_bar_subtitle_binding != null) {
-                       right_header_bar_subtitle_binding.unbind ();
-                       right_header_bar_subtitle_binding = null;
-               }
-               if (right_header_bar_title_binding != null) {
-                       right_header_bar_title_binding.unbind ();
-                       right_header_bar_title_binding = null;
-               }
+               right_header_bar_binding = page.bind_property ("header-bar", this, "right_header_bar",
+                                                              BindingFlags.SYNC_CREATE);
+               immersive_mode_binding = page.bind_property ("immersive-mode", this, "immersive-mode",
+                                                              BindingFlags.SYNC_CREATE);
        }
 }
diff --git a/src/ui/reset-gamepad-mapping-dialog.vala b/src/ui/reset-gamepad-mapping-dialog.vala
new file mode 100644
index 0000000..adff3e0
--- /dev/null
+++ b/src/ui/reset-gamepad-mapping-dialog.vala
@@ -0,0 +1,5 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/ui/reset-gamepad-mapping-dialog.ui")]
+public class Games.ResetGamepadMappingDialog : Gtk.MessageDialog {
+}



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