[gnome-games/wip/abhinavsingh/gamepad-config] ui/gamepad: Temporary patch for GamepadMapper
- From: Abhinav Singh <abhinavsingh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/wip/abhinavsingh/gamepad-config] ui/gamepad: Temporary patch for GamepadMapper
- Date: Fri, 12 May 2017 08:25:05 +0000 (UTC)
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]