|
20 | 20 | */ |
21 | 21 |
|
22 | 22 | public class Spice.GamepadSlideController : Object { |
23 | | - private static GamepadSlideController? instance = null; |
24 | | - private unowned SlideManager slide_manager; |
| 23 | + public signal void raw_button (int button); |
| 24 | + |
| 25 | + private static Spice.GamepadSlideController? instance = null; |
| 26 | + private unowned Spice.SlideManager slide_manager; |
| 27 | + private unowned Spice.Window window; |
25 | 28 |
|
26 | 29 | private LibGamepad.GamepadMonitor gamepad_monitor; |
27 | 30 | private LibGamepad.Gamepad[] gamepads = {}; |
28 | 31 |
|
29 | | - public static void startup (SlideManager _slide_manager) { |
| 32 | + private Granite.Widgets.Toast? toast = null; |
| 33 | + private ControlerConfiguration? config = null; |
| 34 | + |
| 35 | + public bool editing = false; |
| 36 | + |
| 37 | + public static void startup (SlideManager _slide_manager, Spice.Window window) { |
30 | 38 | if (instance == null) { |
31 | | - instance = new GamepadSlideController (); |
| 39 | + instance = new GamepadSlideController (window); |
32 | 40 | } |
33 | 41 |
|
34 | 42 | instance.slide_manager = _slide_manager; |
35 | 43 | } |
36 | 44 |
|
37 | | - private GamepadSlideController () { |
| 45 | + private GamepadSlideController (Spice.Window window) { |
| 46 | + this.window = window; |
38 | 47 | gamepad_monitor = new LibGamepad.GamepadMonitor (); |
39 | 48 |
|
40 | | - // On plugin, connect signals to the gamepad and store it in the gamepads array so it is not deleted by reference counting |
41 | | - gamepad_monitor.gamepad_plugged.connect ((gamepad) => { |
42 | | - print (@"GM Plugged in $(gamepad.raw_gamepad.identifier)- $(gamepad.raw_name)\n"); |
43 | | - gamepads += gamepad; |
44 | | - // Bind events |
45 | | - gamepad.button_event.connect (button_event); |
46 | | - //gamepad.axis_event.connect ((axis, value) => print (@"$(gamepad.raw_name) - $(axis.to_string ()) - $value\n")); |
47 | | - gamepad.unplugged.connect (() => print (@"$(gamepad.raw_name) - G Unplugged\n")); |
48 | | - }); |
49 | | - |
50 | | - // Initialize initially plugged in gamepads |
51 | | - gamepad_monitor.foreach_gamepad ((gamepad) => { |
52 | | - print (@"GM Initially Plugged in $(gamepad.raw_gamepad.identifier) - $(gamepad.guid) - $(gamepad.raw_name)\n"); |
53 | | - gamepads += gamepad; |
54 | | - // Bind events |
55 | | - gamepad.button_event.connect (button_event); |
56 | | - //gamepad.axis_event.connect ((axis, value) => print (@"$(gamepad.name) - $(axis.to_string ()) - $value\n")); |
57 | | - gamepad.unplugged.connect (() => print (@"$(gamepad.raw_name) - G Unplugged\n")); |
58 | | - }); |
| 49 | + gamepad_monitor.gamepad_plugged.connect (connect_gamepad); |
| 50 | + gamepad_monitor.foreach_gamepad (connect_gamepad); |
| 51 | + } |
| 52 | + |
| 53 | + private void connect_gamepad (LibGamepad.Gamepad gamepad) { |
| 54 | + debug ("Controler Plugged in %s, %s", gamepad.raw_gamepad.identifier, gamepad.raw_name); |
| 55 | + gamepads += gamepad; |
| 56 | + |
| 57 | + config = new ControlerConfiguration (); |
| 58 | + |
| 59 | + gamepad.button_event.connect (button_event); |
| 60 | + gamepad.unplugged.connect (() => debug (@"$(gamepad.raw_name) - G Unplugged\n")); |
| 61 | + show_controller_toast (); |
| 62 | + } |
| 63 | + |
| 64 | + private void show_controller_toast () { |
| 65 | + if (toast == null) { |
| 66 | + toast = new Granite.Widgets.Toast (_("Controller found")); |
| 67 | + toast.set_default_action (_("Set up…")); |
| 68 | + |
| 69 | + toast.default_action.connect (() => { |
| 70 | + var dialog = new ControllerConfigurationDialog (this, this.config); |
| 71 | + dialog.present (); |
| 72 | + }); |
| 73 | + } |
| 74 | + |
| 75 | + this.window.add_toast_notification (toast); |
59 | 76 | } |
60 | 77 |
|
61 | 78 | private void button_event (int button) { |
62 | 79 | debug ("Gamepad Button event: %d\n", button); |
| 80 | + raw_button (button); |
| 81 | + if (editing) return; |
63 | 82 |
|
64 | | - switch (button) { |
65 | | - case 0: |
66 | | - next_slide (); |
67 | | - break; |
68 | | - case 2: |
69 | | - previous_slide (); |
70 | | - break; |
71 | | - case 12: |
72 | | - toggle_present (); |
73 | | - break; |
74 | | - case 1: |
75 | | - jump_to_checkpoint (); |
76 | | - break; |
77 | | - case 3: |
78 | | - set_checkpoint (); |
79 | | - break; |
| 83 | + if (button == config.next) { |
| 84 | + next_slide (); |
| 85 | + } else if (button == config.back) { |
| 86 | + previous_slide (); |
| 87 | + } else if (button == config.checkpoint) { |
| 88 | + set_checkpoint (); |
| 89 | + } else if (button == config.jump) { |
| 90 | + jump_to_checkpoint (); |
| 91 | + } else if (button == config.home) { |
| 92 | + toggle_present (); |
80 | 93 | } |
81 | 94 | } |
82 | 95 |
|
@@ -107,4 +120,165 @@ public class Spice.GamepadSlideController : Object { |
107 | 120 | window.fullscreen (); |
108 | 121 | } |
109 | 122 | } |
| 123 | + |
| 124 | + private class ControllerConfigurationDialog : Gtk.Dialog { |
| 125 | + private unowned ControlerConfiguration config; |
| 126 | + private unowned GamepadSlideController monitor; |
| 127 | + |
| 128 | + private Gtk.Grid grid; |
| 129 | + private Gtk.Widget save_button; |
| 130 | + |
| 131 | + private bool listening = false; |
| 132 | + private int** listening_action = null; |
| 133 | + private Gtk.Button listening_button; |
| 134 | + |
| 135 | + private int row = 0; |
| 136 | + |
| 137 | + public ControllerConfigurationDialog (GamepadSlideController monitor, ControlerConfiguration _config) { |
| 138 | + this.monitor = monitor; |
| 139 | + this.config = _config; |
| 140 | + |
| 141 | + monitor.editing = true; |
| 142 | + |
| 143 | + this.set_border_width (12); |
| 144 | + set_titlebar (new Gtk.Grid ()); |
| 145 | + set_keep_above (true); |
| 146 | + set_size_request (360, 400); |
| 147 | + resizable = false; |
| 148 | + modal = true; |
| 149 | + |
| 150 | + var label = new Gtk.Label (_("Controller Configuration")); |
| 151 | + label.get_style_context ().add_class ("h4"); |
| 152 | + |
| 153 | + this.grid = new Gtk.Grid (); |
| 154 | + grid.orientation = Gtk.Orientation.VERTICAL; |
| 155 | + grid.column_spacing = 12; |
| 156 | + grid.row_spacing = 6; |
| 157 | + |
| 158 | + grid.attach (label, 0, row++, 1, 1); |
| 159 | + add_row (_("Next Slide:"), &(config.next)); |
| 160 | + add_row (_("Previous Slide:"), &(config.back)); |
| 161 | + add_row (_("Set Jump:"), &(config.checkpoint)); |
| 162 | + add_row (_("Jump to slide:"), &(config.jump)); |
| 163 | + add_row (_("Toggle Presentation:"), &(config.home)); |
| 164 | + |
| 165 | + get_content_area ().add (grid); |
| 166 | + add_button (_("Cancel"), 2); |
| 167 | + save_button = add_button (_("Apply"), 1); |
| 168 | + |
| 169 | + response.connect ((ID) => { |
| 170 | + switch (ID) { |
| 171 | + case 1: |
| 172 | + config.save (); |
| 173 | + break; |
| 174 | + } |
| 175 | + |
| 176 | + listening = false; |
| 177 | + monitor.editing = false; |
| 178 | + this.close (); |
| 179 | + }); |
| 180 | + |
| 181 | + monitor.raw_button.connect ((id) => { |
| 182 | + if (!this.listening) return; |
| 183 | + this.listening = false; |
| 184 | + |
| 185 | + debug ("Event caught %d\n", id); |
| 186 | + |
| 187 | + **listening_action = id; |
| 188 | + listening_button.label = _("Button %d").printf (id); |
| 189 | + |
| 190 | + save_button.sensitive = config.is_valid (); |
| 191 | + }); |
| 192 | + |
| 193 | + this.show_all (); |
| 194 | + } |
| 195 | + |
| 196 | + public void add_row (string name, int* action) { |
| 197 | + var label = new Gtk.Label (name); |
| 198 | + label.halign = Gtk.Align.END; |
| 199 | + |
| 200 | + var button = new Gtk.Button.with_label (_("Button %d").printf (*action)); |
| 201 | + button.clicked.connect (() => { |
| 202 | + if (listening) { |
| 203 | + listening_button.label = _("Button %d").printf (**listening_action); |
| 204 | + } |
| 205 | + |
| 206 | + if (!listening || this.listening_button != button) { |
| 207 | + this.listening = true; |
| 208 | + this.listening_action = &action; |
| 209 | + this.listening_button = button; |
| 210 | + button.label = _("..."); |
| 211 | + save_button.sensitive = false; |
| 212 | + } else if (listening && this.listening_button == button) { |
| 213 | + this.listening = false; |
| 214 | + this.listening_button = null; |
| 215 | + save_button.sensitive = config.is_valid (); |
| 216 | + } |
| 217 | + }); |
| 218 | + |
| 219 | + this.grid.attach (label, 0, row, 1, 1); |
| 220 | + this.grid.attach (button, 1, row++, 1, 1); |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + private class ControlerConfiguration : Object { |
| 225 | + // Defaults to JoyCon's Configuration |
| 226 | + public int next = 0; |
| 227 | + public int back = 2; |
| 228 | + public int checkpoint = 3; |
| 229 | + public int jump = 1; |
| 230 | + public int home = 12; |
| 231 | + |
| 232 | + public ControlerConfiguration () { |
| 233 | + load (); |
| 234 | + } |
| 235 | + |
| 236 | + public bool is_valid () { |
| 237 | + var buttons = new Array<int>(); |
| 238 | + buttons.append_val (next); |
| 239 | + |
| 240 | + if (back in buttons.data) return false; |
| 241 | + buttons.append_val (back); |
| 242 | + |
| 243 | + if (checkpoint in buttons.data) return false; |
| 244 | + buttons.append_val (checkpoint); |
| 245 | + |
| 246 | + if (jump in buttons.data) return false; |
| 247 | + buttons.append_val (jump); |
| 248 | + |
| 249 | + if (home in buttons.data) return false; |
| 250 | + buttons.append_val (home); |
| 251 | + |
| 252 | + return true; |
| 253 | + } |
| 254 | + |
| 255 | + public void load () { |
| 256 | + var config = Spice.Services.Settings.get_instance ().controler_config; |
| 257 | + if (config == "") { |
| 258 | + save (); |
| 259 | + return; |
| 260 | + } |
| 261 | + |
| 262 | + try { |
| 263 | + var parser = new Json.Parser (); |
| 264 | + parser.load_from_data (config); |
| 265 | + |
| 266 | + var root = parser.get_root ().get_object (); |
| 267 | + |
| 268 | + next = (int) root.get_int_member ("next"); |
| 269 | + back = (int) root.get_int_member ("back"); |
| 270 | + checkpoint = (int) root.get_int_member ("checkpoint"); |
| 271 | + jump = (int) root.get_int_member ("jump"); |
| 272 | + home = (int) root.get_int_member ("home"); |
| 273 | + } catch (Error e) { |
| 274 | + warning ("Error loading controler config: %s", e.message); |
| 275 | + save (); |
| 276 | + } |
| 277 | + } |
| 278 | + |
| 279 | + public void save () { |
| 280 | + var config = """{"next":%d, "back":%d, "checkpoint":%d, "jump":%d, "home":%d }""".printf (next, back, checkpoint, jump, home); |
| 281 | + Spice.Services.Settings.get_instance ().controler_config = config; |
| 282 | + } |
| 283 | + } |
110 | 284 | } |
0 commit comments