new controls dialog; using gconf instead of hgw
[drnoksnes] / gui / keys.c
1 /*
2 * This file is part of DrNokSnes
3 *
4 * Copyright (C) 2009 Javier S. Pedro <maemo@javispedro.com>
5 *
6 * This software is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * This software is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this software; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23 #include <string.h>
24 #include <gtk/gtk.h>
25 #include <hildon/hildon-helper.h>
26
27 #if MAEMO_VERSION >= 5
28 #include <hildon/hildon-gtk.h>
29 #include <hildon/hildon-pannable-area.h>
30 #include <hildon/hildon-check-button.h>
31 #endif
32
33 #include "../platform/hgw.h"
34 #include "plugin.h"
35 #include "gconf.h"
36 #include "cellrendererkey.h"
37 #include "i18n.h"
38
39 static GtkDialog* dialog;
40 static int current_player;
41 #if MAEMO_VERSION >= 5
42 static HildonPannableArea* keys_scroll;
43 #else
44 static GtkScrolledWindow* keys_scroll;
45 #endif
46 static GtkListStore* keys_store;
47 static GtkTreeView* keys_list;
48
49 #define DIALOG_RESPONSE_DEFAULTS 1
50
51 enum
52 {
53   BUTTON_COLUMN,
54   BUTTONENTRY_COLUMN,
55   N_COLUMNS
56 };
57
58 typedef struct ButtonEntry {
59         const char * name;
60         const char * gconf_key;
61         unsigned char scancode;
62         gboolean changed;
63 } ButtonEntry;
64
65 static ButtonEntry buttons[] = {
66 #define HELP(...)
67 #define BUTTON(description, slug, actions, d, f) \
68         { description, G_STRINGIFY(slug), 0 },
69 #define ACTION(description, slug, actions, d, f) \
70         { description, G_STRINGIFY(slug), 0 },
71 #define LAST \
72         { 0 }
73 #include "buttons.inc"
74 #undef HELP
75 #undef BUTTON
76 #undef ACTION
77 #undef LAST
78 };
79
80 typedef struct 
81 {
82         gchar key_base[kGConfPlayerPathBufferLen];
83         int key_len;
84         gchar *key;
85 } IteratorData;
86
87 static gboolean load_key_config(GtkTreeModel *model, GtkTreePath *path,
88                                                                 GtkTreeIter *iter, gpointer data)
89 {
90         IteratorData *idata = (IteratorData*)data;
91         ButtonEntry *button_entry;
92
93         gtk_tree_model_get(model, iter,
94                 BUTTONENTRY_COLUMN, &button_entry,
95                 -1);
96
97         strcpy(idata->key, button_entry->gconf_key);
98         int scancode = gconf_client_get_int(gcc, idata->key_base, NULL);
99
100         button_entry->scancode = scancode;
101         button_entry->changed = FALSE;
102
103         gtk_tree_model_row_changed(GTK_TREE_MODEL(keys_store), path, iter);
104
105         return FALSE;
106 }
107
108 static void load_settings()
109 {
110         IteratorData idata;
111         idata.key_len = sprintf(idata.key_base,
112                 kGConfPlayerPath kGConfPlayerKeyboardPath "/", current_player);
113         idata.key = idata.key_base + idata.key_len;
114         gtk_tree_model_foreach(GTK_TREE_MODEL(keys_store), load_key_config, &idata);
115 }
116
117 static gboolean save_key_config(GtkTreeModel *model, GtkTreePath *path,
118                                                                 GtkTreeIter *iter, gpointer data)
119 {
120         IteratorData *idata = (IteratorData*)data;
121         ButtonEntry *button_entry;
122
123         gtk_tree_model_get(model, iter,
124                 BUTTONENTRY_COLUMN, &button_entry,
125                 -1);
126
127         if (button_entry->changed) {
128                 strcpy(idata->key, button_entry->gconf_key);
129                 gconf_client_set_int(gcc, idata->key_base, button_entry->scancode, NULL);
130                 button_entry->changed = FALSE;
131         }
132
133         gtk_tree_model_row_changed(GTK_TREE_MODEL(keys_store), path, iter);
134
135         return FALSE;
136 }
137
138 static void save_settings()
139 {
140         IteratorData idata;
141         idata.key_len = sprintf(idata.key_base,
142                 kGConfPlayerPath kGConfPlayerKeyboardPath "/", current_player);
143         idata.key = idata.key_base + idata.key_len;
144         gtk_tree_model_foreach(GTK_TREE_MODEL(keys_store), save_key_config, &idata);
145 }
146
147 static gboolean get_default_key_config(GtkTreeModel *model, GtkTreePath *path,
148                                                                 GtkTreeIter *iter, gpointer data)
149 {
150         IteratorData *idata = (IteratorData*)data;
151         ButtonEntry *button_entry;
152
153         gtk_tree_model_get(model, iter,
154                 BUTTONENTRY_COLUMN, &button_entry,
155                 -1);
156
157         strcpy(idata->key, button_entry->gconf_key);
158         GConfValue *value = gconf_client_get_default_from_schema(gcc,
159                 idata->key_base, NULL);
160         if (value) {
161                 int scancode = gconf_value_get_int(value);
162                 if (button_entry->scancode != scancode) {
163                         button_entry->scancode = scancode;
164                         button_entry->changed = TRUE;
165                 }
166                 gconf_value_free(value);
167         }
168
169         gtk_tree_model_row_changed(GTK_TREE_MODEL(keys_store), path, iter);
170
171         return FALSE;
172 }
173
174 static void get_default_settings()
175 {
176         IteratorData idata;
177         idata.key_len = sprintf(idata.key_base,
178                 kGConfPlayerPath kGConfPlayerKeyboardPath "/", current_player);
179         idata.key = idata.key_base + idata.key_len;
180         gtk_tree_model_foreach(GTK_TREE_MODEL(keys_store),
181                 get_default_key_config, &idata);
182 }
183
184 static void
185 accel_set_func (GtkTreeViewColumn *tree_column,
186                 GtkCellRenderer   *cell,
187                 GtkTreeModel      *model,
188                 GtkTreeIter       *iter,
189                 gpointer           data)
190 {
191         ButtonEntry *button_entry;
192
193         gtk_tree_model_get (model, iter,
194                                                 BUTTONENTRY_COLUMN, &button_entry,
195                                                 -1);
196
197         if (button_entry == NULL) {
198                 g_object_set (G_OBJECT (cell),
199                         "visible", FALSE,
200                         NULL);
201         } else {
202                 g_object_set (G_OBJECT (cell),
203                         "visible", TRUE,
204                         "editable", TRUE,
205                         "scancode", button_entry->scancode,
206                         "style", PANGO_STYLE_NORMAL,
207                         NULL);
208         }
209 }
210
211 static void
212 cb_key_edited(GtkCellRendererText *cell, const char *path_string,
213         guint scancode, gpointer data)
214 {
215         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
216         GtkTreeIter iter;
217         ButtonEntry *button_entry;
218
219         gtk_tree_model_get_iter(GTK_TREE_MODEL(keys_store), &iter, path);
220         gtk_tree_model_get(GTK_TREE_MODEL(keys_store), &iter,
221                 BUTTONENTRY_COLUMN, &button_entry,
222                 -1);
223
224         button_entry->scancode = scancode;
225         button_entry->changed = TRUE;
226
227         gtk_tree_model_row_changed(GTK_TREE_MODEL(keys_store), path, &iter);
228         gtk_tree_path_free(path);
229 }
230
231 static void
232 cb_key_cleared(GtkCellRendererText *cell, const char *path_string,
233         gpointer data)
234 {
235         GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
236         GtkTreeIter iter;
237         ButtonEntry *button_entry;
238
239         gtk_tree_model_get_iter(GTK_TREE_MODEL(keys_store), &iter, path);
240         gtk_tree_model_get(GTK_TREE_MODEL(keys_store), &iter,
241                 BUTTONENTRY_COLUMN, &button_entry,
242                 -1);
243
244         button_entry->scancode = 0;
245         button_entry->changed = TRUE;
246
247         gtk_tree_model_row_changed(GTK_TREE_MODEL(keys_store), path, &iter);
248         gtk_tree_path_free(path);
249 }
250
251 static void cb_dialog_response(GtkWidget * sender, gint response, gpointer data)
252 {
253         if (response == DIALOG_RESPONSE_DEFAULTS) {
254                 get_default_settings();
255                 return;
256         }
257
258         if (response == GTK_RESPONSE_OK) {
259                 save_settings();
260         }
261
262         gtk_widget_destroy(GTK_WIDGET(dialog));
263 }
264
265 void keys_dialog(GtkWindow* parent, int player)
266 {
267         gchar* title = g_strdup_printf(_("Player %d keys"), player);
268         dialog = GTK_DIALOG(gtk_dialog_new_with_buttons(title,
269                 parent, GTK_DIALOG_MODAL,
270                 _("Defaults"), DIALOG_RESPONSE_DEFAULTS,
271                 GTK_STOCK_SAVE, GTK_RESPONSE_OK,
272                 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL));
273         g_free(title);
274
275         current_player = player;
276
277         keys_store = GTK_LIST_STORE(gtk_list_store_new(N_COLUMNS,
278                 G_TYPE_STRING, G_TYPE_POINTER));
279 #if MAEMO_VERSION >= 5
280         keys_list = GTK_TREE_VIEW(hildon_gtk_tree_view_new_with_model(
281                 HILDON_UI_MODE_EDIT, GTK_TREE_MODEL(keys_store)));
282         keys_scroll = HILDON_PANNABLE_AREA(hildon_pannable_area_new());
283 #else
284         keys_list = GTK_TREE_VIEW(
285                 gtk_tree_view_new_with_model(GTK_TREE_MODEL(keys_store)));
286         keys_scroll = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL, NULL));
287         gtk_scrolled_window_set_policy(keys_scroll,
288                 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
289 #endif
290
291         GtkCellRenderer* renderer = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
292         GtkTreeViewColumn * column =
293                  gtk_tree_view_column_new_with_attributes ("Button",
294                         gtk_cell_renderer_text_new(),
295                         "text", BUTTON_COLUMN,
296                         NULL);
297         gtk_tree_view_column_set_resizable(column, FALSE);
298         gtk_tree_view_column_set_expand(column, TRUE);
299         gtk_tree_view_append_column(keys_list, column);
300
301         renderer = GTK_CELL_RENDERER(cell_renderer_key_new());
302         column = gtk_tree_view_column_new_with_attributes("Key", renderer, NULL);
303         gtk_tree_view_column_set_cell_data_func(column, renderer, accel_set_func, NULL, NULL);
304         gtk_tree_view_column_set_resizable(column, FALSE);
305 #if MAEMO_VERSION >= 5
306         gtk_tree_view_column_set_min_width(column, 340);
307 #else
308         gtk_tree_view_column_set_min_width(column, 250);
309 #endif
310         gtk_tree_view_append_column(keys_list, column);
311         gtk_tree_view_set_headers_visible(keys_list, TRUE);
312
313         int i;
314         for (i = 0; buttons[i].name; i++) {
315                 GtkTreeIter iter;
316                 gtk_list_store_append(keys_store, &iter);
317                 gtk_list_store_set(keys_store, &iter,
318                         BUTTON_COLUMN, buttons[i].name,
319                         BUTTONENTRY_COLUMN, &buttons[i],
320                         -1);
321         }
322
323 #if MAEMO_VERSION >= 5
324         gtk_window_resize(GTK_WINDOW(dialog), 800, 340);
325 #else
326         gtk_window_resize(GTK_WINDOW(dialog), 600, 340);
327 #endif
328         gtk_container_add(GTK_CONTAINER(keys_scroll), GTK_WIDGET(keys_list));
329         gtk_box_pack_start_defaults(GTK_BOX(dialog->vbox), GTK_WIDGET(keys_scroll));
330
331         load_settings();
332
333         g_signal_connect(G_OBJECT(dialog), "response",
334                                         G_CALLBACK (cb_dialog_response), NULL);
335         g_signal_connect(G_OBJECT(renderer), "accel_edited",
336                                         G_CALLBACK(cb_key_edited), NULL);
337         g_signal_connect(G_OBJECT(renderer), "accel_cleared",
338                     G_CALLBACK(cb_key_cleared), NULL);
339
340         gtk_widget_show_all(GTK_WIDGET(dialog));
341 }
342