filename | src/gtkui/gtk_ctrl.c |
changeset | 1057:6f2158c421bb |
prev | 1043:ec716f2b8ffb |
next | 1065:bc1cc0c54917 |
author | nkeynes |
date | Sun Jun 28 12:08:16 2009 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Fix creating first VMU (failed to add to list) Fix device-changed causing second device-changed to fire |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Define the main (emu) GTK window, along with its menubars,
5 * toolbars, etc.
6 *
7 * Copyright (c) 2005 Nathan Keynes.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 */
20 #include <assert.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
26 #include "lxdream.h"
27 #include "display.h"
28 #include "gtkui/gtkui.h"
29 #include "maple/maple.h"
30 #include "vmu/vmulist.h"
32 #define MAX_DEVICES 4
34 #define LOAD_VMU_TAG ((void *)-1)
35 #define CREATE_VMU_TAG ((void *)-2)
37 static void controller_device_configure(maple_device_t device);
38 static void maple_set_device_selection( GtkWidget *combo, maple_device_t device );
40 struct maple_config_class {
41 const char *name;
42 void (*config_func)(maple_device_t device);
43 };
45 typedef struct maple_slot_data {
46 maple_device_t old_device;
47 maple_device_t new_device;
48 GtkWidget *button;
49 GtkWidget *combo;
50 gboolean primarySlot;
51 } *maple_slot_data_t;
54 static struct maple_config_class maple_device_config[] = {
55 { "Sega Controller", controller_device_configure },
56 { "Sega Lightgun", controller_device_configure },
57 { NULL, NULL } };
59 static struct maple_slot_data maple_data[MAPLE_MAX_DEVICES];
61 /**
62 * Flag set when changing the selection on one of the combo boxes manually -
63 * avoids the followup changed event.
64 */
65 static gboolean maple_device_adjusting = FALSE;
67 static void config_keysym_hook( void *data, const gchar *keysym )
68 {
69 GtkWidget *widget = (GtkWidget *)data;
70 gtk_entry_set_text( GTK_ENTRY(widget), keysym );
71 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
72 input_set_keysym_hook(NULL, NULL);
73 }
75 static gboolean config_key_buttonpress( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
76 {
77 gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
78 if( keypress_mode ) {
79 gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, event->button);
80 if( keysym != NULL ) {
81 config_keysym_hook( widget, keysym );
82 g_free(keysym);
83 }
84 return TRUE;
85 } else {
86 gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
87 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
88 input_set_keysym_hook(config_keysym_hook, widget);
89 }
90 return FALSE;
91 }
93 static gboolean config_key_keypress( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
94 {
95 gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
96 if( keypress_mode ) {
97 if( event->keyval == GDK_Escape ) {
98 gtk_entry_set_text( GTK_ENTRY(widget), "" );
99 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
100 return TRUE;
101 }
102 GdkKeymap *keymap = gdk_keymap_get_default();
103 guint keyval;
105 gdk_keymap_translate_keyboard_state( keymap, event->hardware_keycode, 0, 0, &keyval,
106 NULL, NULL, NULL );
107 gtk_entry_set_text( GTK_ENTRY(widget), gdk_keyval_name(keyval) );
108 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
109 input_set_keysym_hook(NULL, NULL);
110 return TRUE;
111 } else {
112 switch( event->keyval ) {
113 case GDK_Return:
114 case GDK_KP_Enter:
115 gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
116 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
117 input_set_keysym_hook(config_keysym_hook, widget);
118 return TRUE;
119 case GDK_BackSpace:
120 case GDK_Delete:
121 gtk_entry_set_text( GTK_ENTRY(widget), "" );
122 return TRUE;
123 }
124 return FALSE;
125 }
127 }
129 static void controller_config_done( GtkWidget *panel, gboolean isOK )
130 {
131 if( isOK ) {
132 maple_device_t device = (maple_device_t)gtk_object_get_data( GTK_OBJECT(panel), "maple_device" );
133 lxdream_config_entry_t conf = device->get_config(device);
134 int i;
135 for( i=0; conf[i].key != NULL; i++ ) {
136 char buf[64];
137 GtkWidget *entry1, *entry2;
138 const gchar *key1, *key2;
139 snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
140 entry1 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
141 key1 = gtk_entry_get_text(GTK_ENTRY(entry1));
142 snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
143 entry2 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
144 key2 = gtk_entry_get_text(GTK_ENTRY(entry2));
145 if( key1 == NULL || key1[0] == '\0') {
146 lxdream_set_config_value( &conf[i], key2 );
147 } else if( key2 == NULL || key2[0] == '\0') {
148 lxdream_set_config_value( &conf[i], key1 );
149 } else {
150 char buf[64];
151 snprintf( buf, sizeof(buf), "%s, %s", key1, key2 );
152 lxdream_set_config_value( &conf[i], buf );
153 }
154 }
155 }
156 input_set_keysym_hook(NULL, NULL);
157 }
159 static void controller_device_configure( maple_device_t device )
160 {
161 lxdream_config_entry_t conf = maple_get_device_config(device);
162 int count, i;
163 for( count=0; conf[count].key != NULL; count++ );
165 GtkWidget *table = gtk_table_new( (count+1)>>1, 6, FALSE );
166 GList *focus_chain = NULL;
167 gtk_object_set_data( GTK_OBJECT(table), "maple_device", device );
168 for( i=0; i<count; i++ ) {
169 GtkWidget *text, *text2;
170 char buf[64];
171 int x=0;
172 int y=i;
173 if( i >= (count+1)>>1 ) {
174 x = 3;
175 y -= (count+1)>>1;
176 }
177 gtk_table_attach( GTK_TABLE(table), gtk_label_new(gettext(conf[i].label)), x, x+1, y, y+1,
178 GTK_SHRINK, GTK_SHRINK, 0, 0 );
179 text = gtk_entry_new();
180 gtk_entry_set_width_chars( GTK_ENTRY(text), 11 );
181 gtk_entry_set_editable( GTK_ENTRY(text), FALSE );
182 g_signal_connect( text, "key_press_event",
183 G_CALLBACK(config_key_keypress), NULL );
184 g_signal_connect( text, "button_press_event",
185 G_CALLBACK(config_key_buttonpress), NULL );
186 snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
187 g_object_set_data( G_OBJECT(text), "keypress_mode", GINT_TO_POINTER(FALSE) );
188 g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text );
189 gtk_table_attach_defaults( GTK_TABLE(table), text, x+1, x+2, y, y+1);
190 focus_chain = g_list_append( focus_chain, text );
191 text2 = gtk_entry_new();
192 gtk_entry_set_width_chars( GTK_ENTRY(text2), 11 );
193 gtk_entry_set_editable( GTK_ENTRY(text2), FALSE );
194 g_signal_connect( text2, "key_press_event",
195 G_CALLBACK(config_key_keypress), NULL );
196 g_signal_connect( text2, "button_press_event",
197 G_CALLBACK(config_key_buttonpress), NULL );
198 snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
199 g_object_set_data( G_OBJECT(text2), "keypress_mode", GINT_TO_POINTER(FALSE) );
200 g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text2 );
201 gtk_table_attach_defaults( GTK_TABLE(table), text2, x+2, x+3, y, y+1);
202 focus_chain = g_list_append( focus_chain, text2 );
203 if( conf[i].value != NULL ) {
204 gchar **parts = g_strsplit(conf[i].value,",",3);
205 if( parts[0] != NULL ) {
206 gtk_entry_set_text( GTK_ENTRY(text), g_strstrip(parts[0]) );
207 if( parts[1] != NULL ) {
208 gtk_entry_set_text( GTK_ENTRY(text2), g_strstrip(parts[1]) );
209 }
210 }
211 g_strfreev(parts);
212 }
213 }
214 gtk_container_set_focus_chain( GTK_CONTAINER(table), focus_chain );
215 gtk_gui_run_property_dialog( _("Controller Configuration"), table, controller_config_done );
216 }
218 static gboolean maple_properties_activated( GtkButton *button, gpointer user_data )
219 {
220 maple_slot_data_t data = (maple_slot_data_t)user_data;
221 if( data->new_device != NULL ) {
222 int i;
223 for( i=0; maple_device_config[i].name != NULL; i++ ) {
224 if( strcmp(data->new_device->device_class->name, maple_device_config[i].name) == 0 ) {
225 if( data->new_device == data->old_device ) {
226 // Make a copy at this point if we haven't already
227 data->new_device = data->old_device->clone(data->old_device);
228 }
229 maple_device_config[i].config_func(data->new_device);
230 break;
231 }
232 }
233 if( maple_device_config[i].name == NULL ) {
234 gui_error_dialog( _("No configuration page available for device type") );
235 }
236 }
237 return TRUE;
238 }
240 static gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data )
241 {
242 if( maple_device_adjusting ) {
243 return TRUE;
244 }
246 maple_slot_data_t data = (maple_slot_data_t)user_data;
247 int active = gtk_combo_box_get_active(combo), i;
248 gboolean has_config = FALSE;
249 gboolean set_selection = FALSE;
250 int has_slots = 0;
251 if( active != 0 ) {
252 GtkTreeIter iter;
253 maple_device_class_t devclz;
254 const gchar *vmu_filename;
256 GtkTreeModel *model = gtk_combo_box_get_model(combo);
257 gtk_combo_box_get_active_iter(combo, &iter);
258 gtk_tree_model_get(model, &iter, 1, &devclz, 2, &vmu_filename, -1 );
260 if( devclz == LOAD_VMU_TAG ) {
261 devclz = NULL;
262 vmu_filename = open_file_dialog( _("Load VMU"), "*.vmu", "VMU Files",
263 CONFIG_VMU_PATH );
264 if( vmu_filename != NULL ) {
265 vmu_volume_t vol = vmu_volume_load( vmu_filename );
266 if( vol != NULL ) {
267 devclz = &vmu_class;
268 vmulist_add_vmu(vmu_filename, vol);
269 set_selection = TRUE;
270 } else {
271 ERROR( "Unable to load VMU file (not a valid VMU)" );
272 }
273 }
274 } else if( devclz == CREATE_VMU_TAG ) {
275 devclz = NULL;
276 vmu_filename = save_file_dialog( _("Create VMU"), "*.vmu", "VMU Files",
277 CONFIG_VMU_PATH );
278 if( vmu_filename != NULL ) {
279 devclz = &vmu_class;
280 set_selection = TRUE;
281 int idx = vmulist_create_vmu( vmu_filename, FALSE );
282 if( idx == -1 ) {
283 ERROR( "Unable to save VMU file: %s", strerror(errno) );
284 }
285 }
286 } else if( vmu_filename != NULL ) {
287 devclz = &vmu_class;
288 }
290 if( devclz == NULL ) {
291 maple_set_device_selection(data->combo, data->new_device);
292 return TRUE;
293 }
295 if( data->new_device != NULL ) {
296 if( data->new_device->device_class != devclz ) {
297 if( data->new_device != data->old_device ) {
298 data->new_device->destroy(data->new_device);
299 }
300 data->new_device = devclz->new_device();
301 }
302 } else {
303 data->new_device = devclz->new_device();
304 }
305 has_config = data->new_device != NULL && data->new_device->get_config != NULL && !MAPLE_IS_VMU(data->new_device);
306 has_slots = data->new_device == NULL ? 0 : MAPLE_SLOTS(devclz);
307 if( MAPLE_IS_VMU(data->new_device) ) {
308 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
309 if( maple_data[i].new_device != NULL && MAPLE_IS_VMU(maple_data[i].new_device) &&
310 MAPLE_VMU_HAS_NAME(maple_data[i].new_device, vmu_filename) ) {
311 maple_data[i].new_device->destroy(maple_data[i].new_device);
312 maple_data[i].new_device = NULL;
313 gtk_combo_box_set_active(maple_data[i].combo,0);
314 }
315 }
316 MAPLE_SET_VMU_NAME(data->new_device,vmu_filename);
317 }
319 if( set_selection ) {
320 maple_set_device_selection(data->combo, data->new_device);
321 }
322 } else {
323 if( data->new_device != NULL && data->new_device != data->old_device ) {
324 data->new_device->destroy(data->new_device);
325 }
326 data->new_device = NULL;
327 }
328 gtk_widget_set_sensitive(data->button, has_config);
330 if( data->primarySlot ) {
331 for( i=0; i<MAPLE_USER_SLOTS; i++ ) {
332 /* This is a little morally dubious... */
333 maple_slot_data_t subdata = data + MAPLE_DEVID(0,(i+1));
334 gtk_widget_set_sensitive(subdata->combo, i < has_slots );
335 gtk_widget_set_sensitive(subdata->button, i < has_slots && subdata->new_device != NULL && subdata->new_device->get_config != NULL && !MAPLE_IS_VMU(subdata->new_device) );
336 }
337 }
338 return TRUE;
339 }
341 static void maple_build_device_model( GtkListStore *dev_model )
342 {
343 const struct maple_device_class **devices = maple_get_device_classes();
344 int i;
346 gtk_list_store_clear(dev_model);
347 gtk_list_store_insert_with_values( dev_model, NULL, 0, 0, _("<empty>"), 1, NULL, 2, NULL, -1 );
348 for( i=0; devices[i] != NULL; i++ ) {
349 if( devices[i]->flags & MAPLE_TYPE_PRIMARY ) {
350 gtk_list_store_insert_with_values( dev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 );
351 }
352 }
354 }
356 /**
357 * (Re)build the subdevice combo-box model.
358 */
359 static void maple_build_subdevice_model( GtkListStore *subdev_model )
360 {
361 int i, j;
362 const struct maple_device_class **devices = maple_get_device_classes();
364 gtk_list_store_clear(subdev_model);
365 gtk_list_store_insert_with_values( subdev_model, NULL, 0, 0, _("<empty>"), 1, NULL, 2, NULL, -1 );
366 for( i=0; devices[i] != NULL; i++ ) {
367 if( !(devices[i]->flags & MAPLE_TYPE_PRIMARY) && !MAPLE_IS_VMU_CLASS(devices[i]) ) {
368 gtk_list_store_insert_with_values( subdev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 );
369 }
370 }
371 for( j=0; j < vmulist_get_size(); j++ ) {
372 gtk_list_store_insert_with_values( subdev_model, NULL, i+j+1, 0, vmulist_get_name(j), 1, NULL, 2, vmulist_get_filename(j), -1 );
373 }
374 gtk_list_store_insert_with_values( subdev_model, NULL, i+j+1, 0, _("Load VMU..."), 1, LOAD_VMU_TAG, 2, NULL, -1 );
375 gtk_list_store_insert_with_values( subdev_model, NULL, i+j+2, 0, _("Create VMU..."), 1, CREATE_VMU_TAG, 2, NULL, -1 );
376 }
378 static gboolean maple_vmulist_changed( vmulist_change_type_t type, int idx, void *data )
379 {
380 GtkListStore *list = (GtkListStore *)data;
381 GtkTreeIter iter;
382 int i,j;
384 /* Search for the row and update accordingly. There's probably better ways
385 * to do this
386 */
388 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter);
389 while( valid ) {
390 gchar *vmu_filename;
391 gpointer devclz;
392 gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, 1, &devclz, 2, &vmu_filename, -1 );
393 if( vmu_filename != NULL || devclz == LOAD_VMU_TAG || devclz == CREATE_VMU_TAG )
394 break;
395 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter);
396 }
397 if( valid ) {
398 for( i=0; i<idx && valid; i++ ) {
399 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter);
400 }
401 }
402 if( valid ) {
403 if( type == VMU_ADDED ) {
404 GtkTreeIter newiter;
405 gtk_list_store_insert_before(list, &newiter, &iter);
406 gtk_list_store_set(list, &newiter, 0, vmulist_get_name(idx), 1, NULL, 2, vmulist_get_filename(idx), -1 );
407 } else if( type == VMU_REMOVED ) {
408 gtk_list_store_remove(list, &iter );
409 }
410 }
411 return TRUE;
412 }
414 /**
415 * Set the device popup selection based on the device (works for both primary
416 * and secondary devices)
417 */
418 static void maple_set_device_selection( GtkWidget *combo, maple_device_t device )
419 {
420 GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
421 GtkTreeIter iter;
423 maple_device_adjusting = TRUE;
424 if( device == NULL ) {
425 gtk_combo_box_set_active( GTK_COMBO_BOX(combo), 0 );
426 } else {
427 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
428 while( valid ) {
429 const struct maple_device_class *clz;
430 const gchar *vmu_filename;
432 gtk_tree_model_get(model, &iter, 1, &clz, 2, &vmu_filename, -1 );
434 if( device->device_class == clz ) {
435 gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter );
436 break;
437 } else if( vmu_filename != NULL && MAPLE_IS_VMU(device) &&
438 MAPLE_VMU_HAS_NAME(device, vmu_filename) ) {
439 gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter );
440 break;
441 }
443 valid = gtk_tree_model_iter_next(model, &iter);
444 }
445 if( !valid ) {
446 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
447 }
448 }
449 maple_device_adjusting = FALSE;
450 }
452 static void maple_dialog_done( GtkWidget *panel, gboolean isOK )
453 {
454 void *p = g_object_get_data( G_OBJECT(panel), "subdev_model" );
455 unregister_vmulist_change_hook( maple_vmulist_changed, p );
457 if( isOK ) {
458 int i;
459 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
460 if( maple_data[i].new_device != maple_data[i].old_device ) {
461 if( maple_data[i].old_device != NULL ) {
462 maple_detach_device(MAPLE_DEVID_PORT(i),MAPLE_DEVID_SLOT(i));
463 }
464 if( maple_data[i].new_device != NULL ) {
465 maple_attach_device(maple_data[i].new_device, MAPLE_DEVID_PORT(i), MAPLE_DEVID_SLOT(i) );
466 }
467 }
468 }
469 lxdream_save_config();
470 } else {
471 int i;
472 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
473 if( maple_data[i].new_device != NULL &&
474 maple_data[i].new_device != maple_data[i].old_device ) {
475 maple_data[i].new_device->destroy(maple_data[i].new_device);
476 }
477 }
478 }
480 }
482 static GtkWidget *maple_panel_new()
483 {
484 GtkWidget *table = gtk_table_new( MAPLE_PORTS * (MAPLE_USER_SLOTS+1), 3, TRUE);
485 int i,j,k;
486 const struct maple_device_class **devices = maple_get_device_classes();
488 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
489 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
490 maple_device_adjusting = FALSE;
492 /* Device models */
493 GtkListStore *dev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
494 maple_build_device_model(dev_model);
496 GtkListStore *subdev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
497 maple_build_subdevice_model(subdev_model);
498 g_object_set_data( G_OBJECT(table), "subdev_model", subdev_model );
499 register_vmulist_change_hook( maple_vmulist_changed, subdev_model );
501 int y =0;
502 for( i=0; i< MAPLE_PORTS; i++ ) {
503 char buf[16];
504 GtkWidget *combo, *button;
505 int length = 1;
506 maple_device_t device = maple_get_device(i,0);
507 int has_slots = device == NULL ? 0 : MAPLE_SLOTS(device->device_class);
509 snprintf( buf, sizeof(buf), _("Port %c."), 'A'+i );
510 gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, y, y+1 );
512 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dev_model));
513 GtkCellRenderer *rend = gtk_cell_renderer_text_new();
514 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE);
515 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 );
516 maple_set_device_selection(combo,device);
517 gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 );
519 button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES );
520 gtk_widget_set_sensitive(button, device != NULL && device->get_config != NULL);
521 gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 );
523 maple_data[MAPLE_DEVID(i,0)].old_device = device;
524 maple_data[MAPLE_DEVID(i,0)].new_device = device;
525 maple_data[MAPLE_DEVID(i,0)].combo = combo;
526 maple_data[MAPLE_DEVID(i,0)].button = button;
527 maple_data[MAPLE_DEVID(i,0)].primarySlot = TRUE;
528 g_signal_connect( button, "clicked",
529 G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,0)] );
530 g_signal_connect( combo, "changed",
531 G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,0)] );
532 y++;
534 for( k=0; k< MAPLE_USER_SLOTS; k++ ) {
535 char tmp[32] = " ";
536 device = maple_get_device(i,k+1);
537 snprintf( tmp+8, sizeof(tmp)-8, _("VMU %d."), (k+1) );
538 gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(tmp), 0, 1, y, y+1 );
539 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(subdev_model));
540 GtkCellRenderer *rend = gtk_cell_renderer_text_new();
541 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE);
542 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 );
543 maple_set_device_selection(combo, device);
545 gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 );
546 button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES );
547 gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 );
548 if( k >= has_slots ) {
549 gtk_widget_set_sensitive(combo, FALSE);
550 gtk_widget_set_sensitive(button, FALSE);
551 } else {
552 gtk_widget_set_sensitive(button, device != NULL && device->get_config != NULL && !MAPLE_IS_VMU(device));
553 }
555 maple_data[MAPLE_DEVID(i,k+1)].old_device = device;
556 maple_data[MAPLE_DEVID(i,k+1)].new_device = device;
557 maple_data[MAPLE_DEVID(i,k+1)].combo = combo;
558 maple_data[MAPLE_DEVID(i,k+1)].button = button;
559 maple_data[MAPLE_DEVID(i,k+1)].primarySlot = FALSE;
560 g_signal_connect( button, "clicked",
561 G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,k+1)] );
562 g_signal_connect( combo, "changed",
563 G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,k+1)] );
564 y++;
565 }
566 gtk_table_set_row_spacing( GTK_TABLE(table), y-1, 10 );
567 }
568 return table;
569 }
571 void maple_dialog_run( )
572 {
573 gtk_gui_run_property_dialog( _("Controller Settings"), maple_panel_new(), maple_dialog_done );
574 }
.