filename | src/gtkui/gtk_ctrl.c |
changeset | 1043:ec716f2b8ffb |
prev | 1036:af7b0c5905dd |
next | 1057:6f2158c421bb |
author | nkeynes |
date | Sat Jun 27 09:55:00 2009 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Ensure each VMU is only attached once Handle removal of sub-devices when detaching parent device |
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 static void config_keysym_hook( void *data, const gchar *keysym )
62 {
63 GtkWidget *widget = (GtkWidget *)data;
64 gtk_entry_set_text( GTK_ENTRY(widget), keysym );
65 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
66 input_set_keysym_hook(NULL, NULL);
67 }
69 static gboolean config_key_buttonpress( GtkWidget *widget, GdkEventButton *event, gpointer user_data )
70 {
71 gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
72 if( keypress_mode ) {
73 gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, event->button);
74 if( keysym != NULL ) {
75 config_keysym_hook( widget, keysym );
76 g_free(keysym);
77 }
78 return TRUE;
79 } else {
80 gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
81 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
82 input_set_keysym_hook(config_keysym_hook, widget);
83 }
84 return FALSE;
85 }
87 static gboolean config_key_keypress( GtkWidget *widget, GdkEventKey *event, gpointer user_data )
88 {
89 gboolean keypress_mode = GPOINTER_TO_INT(g_object_get_data( G_OBJECT(widget), "keypress_mode"));
90 if( keypress_mode ) {
91 if( event->keyval == GDK_Escape ) {
92 gtk_entry_set_text( GTK_ENTRY(widget), "" );
93 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
94 return TRUE;
95 }
96 GdkKeymap *keymap = gdk_keymap_get_default();
97 guint keyval;
99 gdk_keymap_translate_keyboard_state( keymap, event->hardware_keycode, 0, 0, &keyval,
100 NULL, NULL, NULL );
101 gtk_entry_set_text( GTK_ENTRY(widget), gdk_keyval_name(keyval) );
102 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(FALSE) );
103 input_set_keysym_hook(NULL, NULL);
104 return TRUE;
105 } else {
106 switch( event->keyval ) {
107 case GDK_Return:
108 case GDK_KP_Enter:
109 gtk_entry_set_text( GTK_ENTRY(widget), _("<press key>") );
110 g_object_set_data( G_OBJECT(widget), "keypress_mode", GINT_TO_POINTER(TRUE) );
111 input_set_keysym_hook(config_keysym_hook, widget);
112 return TRUE;
113 case GDK_BackSpace:
114 case GDK_Delete:
115 gtk_entry_set_text( GTK_ENTRY(widget), "" );
116 return TRUE;
117 }
118 return FALSE;
119 }
121 }
123 static void controller_config_done( GtkWidget *panel, gboolean isOK )
124 {
125 if( isOK ) {
126 maple_device_t device = (maple_device_t)gtk_object_get_data( GTK_OBJECT(panel), "maple_device" );
127 lxdream_config_entry_t conf = device->get_config(device);
128 int i;
129 for( i=0; conf[i].key != NULL; i++ ) {
130 char buf[64];
131 GtkWidget *entry1, *entry2;
132 const gchar *key1, *key2;
133 snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
134 entry1 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
135 key1 = gtk_entry_get_text(GTK_ENTRY(entry1));
136 snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
137 entry2 = GTK_WIDGET(g_object_get_qdata( G_OBJECT(panel), g_quark_from_string(buf)));
138 key2 = gtk_entry_get_text(GTK_ENTRY(entry2));
139 if( key1 == NULL || key1[0] == '\0') {
140 lxdream_set_config_value( &conf[i], key2 );
141 } else if( key2 == NULL || key2[0] == '\0') {
142 lxdream_set_config_value( &conf[i], key1 );
143 } else {
144 char buf[64];
145 snprintf( buf, sizeof(buf), "%s, %s", key1, key2 );
146 lxdream_set_config_value( &conf[i], buf );
147 }
148 }
149 }
150 input_set_keysym_hook(NULL, NULL);
151 }
153 static void controller_device_configure( maple_device_t device )
154 {
155 lxdream_config_entry_t conf = maple_get_device_config(device);
156 int count, i;
157 for( count=0; conf[count].key != NULL; count++ );
159 GtkWidget *table = gtk_table_new( (count+1)>>1, 6, FALSE );
160 GList *focus_chain = NULL;
161 gtk_object_set_data( GTK_OBJECT(table), "maple_device", device );
162 for( i=0; i<count; i++ ) {
163 GtkWidget *text, *text2;
164 char buf[64];
165 int x=0;
166 int y=i;
167 if( i >= (count+1)>>1 ) {
168 x = 3;
169 y -= (count+1)>>1;
170 }
171 gtk_table_attach( GTK_TABLE(table), gtk_label_new(gettext(conf[i].label)), x, x+1, y, y+1,
172 GTK_SHRINK, GTK_SHRINK, 0, 0 );
173 text = gtk_entry_new();
174 gtk_entry_set_width_chars( GTK_ENTRY(text), 11 );
175 gtk_entry_set_editable( GTK_ENTRY(text), FALSE );
176 g_signal_connect( text, "key_press_event",
177 G_CALLBACK(config_key_keypress), NULL );
178 g_signal_connect( text, "button_press_event",
179 G_CALLBACK(config_key_buttonpress), NULL );
180 snprintf( buf, sizeof(buf), "%s.1", conf[i].key );
181 g_object_set_data( G_OBJECT(text), "keypress_mode", GINT_TO_POINTER(FALSE) );
182 g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text );
183 gtk_table_attach_defaults( GTK_TABLE(table), text, x+1, x+2, y, y+1);
184 focus_chain = g_list_append( focus_chain, text );
185 text2 = gtk_entry_new();
186 gtk_entry_set_width_chars( GTK_ENTRY(text2), 11 );
187 gtk_entry_set_editable( GTK_ENTRY(text2), FALSE );
188 g_signal_connect( text2, "key_press_event",
189 G_CALLBACK(config_key_keypress), NULL );
190 g_signal_connect( text2, "button_press_event",
191 G_CALLBACK(config_key_buttonpress), NULL );
192 snprintf( buf, sizeof(buf), "%s.2", conf[i].key );
193 g_object_set_data( G_OBJECT(text2), "keypress_mode", GINT_TO_POINTER(FALSE) );
194 g_object_set_qdata( G_OBJECT(table), g_quark_from_string(buf), text2 );
195 gtk_table_attach_defaults( GTK_TABLE(table), text2, x+2, x+3, y, y+1);
196 focus_chain = g_list_append( focus_chain, text2 );
197 if( conf[i].value != NULL ) {
198 gchar **parts = g_strsplit(conf[i].value,",",3);
199 if( parts[0] != NULL ) {
200 gtk_entry_set_text( GTK_ENTRY(text), g_strstrip(parts[0]) );
201 if( parts[1] != NULL ) {
202 gtk_entry_set_text( GTK_ENTRY(text2), g_strstrip(parts[1]) );
203 }
204 }
205 g_strfreev(parts);
206 }
207 }
208 gtk_container_set_focus_chain( GTK_CONTAINER(table), focus_chain );
209 gtk_gui_run_property_dialog( _("Controller Configuration"), table, controller_config_done );
210 }
212 static gboolean maple_properties_activated( GtkButton *button, gpointer user_data )
213 {
214 maple_slot_data_t data = (maple_slot_data_t)user_data;
215 if( data->new_device != NULL ) {
216 int i;
217 for( i=0; maple_device_config[i].name != NULL; i++ ) {
218 if( strcmp(data->new_device->device_class->name, maple_device_config[i].name) == 0 ) {
219 if( data->new_device == data->old_device ) {
220 // Make a copy at this point if we haven't already
221 data->new_device = data->old_device->clone(data->old_device);
222 }
223 maple_device_config[i].config_func(data->new_device);
224 break;
225 }
226 }
227 if( maple_device_config[i].name == NULL ) {
228 gui_error_dialog( _("No configuration page available for device type") );
229 }
230 }
231 return TRUE;
232 }
234 static gboolean maple_device_changed( GtkComboBox *combo, gpointer user_data )
235 {
236 maple_slot_data_t data = (maple_slot_data_t)user_data;
237 int active = gtk_combo_box_get_active(combo), i;
238 gboolean has_config = FALSE;
239 gboolean set_selection = FALSE;
240 int has_slots = 0;
241 if( active != 0 ) {
242 GtkTreeIter iter;
243 maple_device_class_t devclz;
244 const gchar *vmu_filename;
246 GtkTreeModel *model = gtk_combo_box_get_model(combo);
247 gtk_combo_box_get_active_iter(combo, &iter);
248 gtk_tree_model_get(model, &iter, 1, &devclz, 2, &vmu_filename, -1 );
250 if( devclz == LOAD_VMU_TAG ) {
251 devclz = NULL;
252 vmu_filename = open_file_dialog( _("Load VMU"), "*.vmu", "VMU Files",
253 CONFIG_VMU_PATH );
254 if( vmu_filename != NULL ) {
255 vmu_volume_t vol = vmu_volume_load( vmu_filename );
256 if( vol != NULL ) {
257 devclz = &vmu_class;
258 vmulist_add_vmu(vmu_filename, vol);
259 set_selection = TRUE;
260 } else {
261 ERROR( "Unable to load VMU file (not a valid VMU)" );
262 }
263 }
264 } else if( devclz == CREATE_VMU_TAG ) {
265 devclz = NULL;
266 vmu_filename = save_file_dialog( _("Create VMU"), "*.vmu", "VMU Files",
267 CONFIG_VMU_PATH );
268 if( vmu_filename != NULL ) {
269 devclz = &vmu_class;
270 set_selection = TRUE;
271 int idx = vmulist_create_vmu( vmu_filename, FALSE );
272 if( idx == -1 ) {
273 ERROR( "Unable to save VMU file: %s", strerror(errno) );
274 }
275 }
276 } else if( vmu_filename != NULL ) {
277 devclz = &vmu_class;
278 }
280 if( devclz == NULL ) {
281 maple_set_device_selection(data->combo, data->new_device);
282 return TRUE;
283 }
285 if( data->new_device != NULL ) {
286 if( data->new_device->device_class != devclz ) {
287 if( data->new_device != data->old_device ) {
288 data->new_device->destroy(data->new_device);
289 }
290 data->new_device = devclz->new_device();
291 }
292 } else {
293 data->new_device = devclz->new_device();
294 }
295 has_config = data->new_device != NULL && data->new_device->get_config != NULL && !MAPLE_IS_VMU(data->new_device);
296 has_slots = data->new_device == NULL ? 0 : MAPLE_SLOTS(devclz);
297 if( MAPLE_IS_VMU(data->new_device) ) {
298 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
299 if( maple_data[i].new_device != NULL && MAPLE_IS_VMU(maple_data[i].new_device) &&
300 MAPLE_VMU_HAS_NAME(maple_data[i].new_device, vmu_filename) ) {
301 maple_data[i].new_device->destroy(maple_data[i].new_device);
302 maple_data[i].new_device = NULL;
303 gtk_combo_box_set_active(maple_data[i].combo,0);
304 }
305 }
306 MAPLE_SET_VMU_NAME(data->new_device,vmu_filename);
307 }
309 if( set_selection ) {
310 maple_set_device_selection(data->combo, data->new_device);
311 }
312 } else {
313 if( data->new_device != NULL && data->new_device != data->old_device ) {
314 data->new_device->destroy(data->new_device);
315 }
316 data->new_device = NULL;
317 }
318 gtk_widget_set_sensitive(data->button, has_config);
320 if( data->primarySlot ) {
321 for( i=0; i<MAPLE_USER_SLOTS; i++ ) {
322 /* This is a little morally dubious... */
323 maple_slot_data_t subdata = data + MAPLE_DEVID(0,(i+1));
324 gtk_widget_set_sensitive(subdata->combo, i < has_slots );
325 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) );
326 }
327 }
328 return TRUE;
329 }
331 static void maple_build_device_model( GtkListStore *dev_model )
332 {
333 const struct maple_device_class **devices = maple_get_device_classes();
334 int i;
336 gtk_list_store_clear(dev_model);
337 gtk_list_store_insert_with_values( dev_model, NULL, 0, 0, _("<empty>"), 1, NULL, 2, NULL, -1 );
338 for( i=0; devices[i] != NULL; i++ ) {
339 if( devices[i]->flags & MAPLE_TYPE_PRIMARY ) {
340 gtk_list_store_insert_with_values( dev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 );
341 }
342 }
344 }
346 /**
347 * (Re)build the subdevice combo-box model.
348 */
349 static void maple_build_subdevice_model( GtkListStore *subdev_model )
350 {
351 int i, j;
352 const struct maple_device_class **devices = maple_get_device_classes();
354 gtk_list_store_clear(subdev_model);
355 gtk_list_store_insert_with_values( subdev_model, NULL, 0, 0, _("<empty>"), 1, NULL, 2, NULL, -1 );
356 for( i=0; devices[i] != NULL; i++ ) {
357 if( !(devices[i]->flags & MAPLE_TYPE_PRIMARY) && !MAPLE_IS_VMU_CLASS(devices[i]) ) {
358 gtk_list_store_insert_with_values( subdev_model, NULL, i+1, 0, devices[i]->name, 1, devices[i], 2, NULL, -1 );
359 }
360 }
361 for( j=0; j < vmulist_get_size(); j++ ) {
362 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 );
363 }
364 gtk_list_store_insert_with_values( subdev_model, NULL, i+j+1, 0, _("Load VMU..."), 1, LOAD_VMU_TAG, 2, NULL, -1 );
365 gtk_list_store_insert_with_values( subdev_model, NULL, i+j+2, 0, _("Create VMU..."), 1, CREATE_VMU_TAG, 2, NULL, -1 );
366 }
368 static gboolean maple_vmulist_changed( vmulist_change_type_t type, int idx, void *data )
369 {
370 GtkListStore *list = (GtkListStore *)data;
371 GtkTreeIter iter;
372 int i,j;
374 /* Search for the row and update accordingly. There's probably better ways
375 * to do this
376 */
378 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter);
379 while( valid ) {
380 gchar *vmu_filename;
381 gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, 2, &vmu_filename, -1 );
382 if( vmu_filename != NULL )
383 break;
384 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter);
385 }
386 if( valid ) {
387 for( i=0; i<idx && valid; i++ ) {
388 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter);
389 }
390 }
391 if( valid ) {
392 if( type == VMU_ADDED ) {
393 GtkTreeIter newiter;
394 gtk_list_store_insert_before(list, &newiter, &iter);
395 gtk_list_store_set(list, &newiter, 0, vmulist_get_name(idx), 1, NULL, 2, vmulist_get_filename(idx), -1 );
396 } else if( type == VMU_REMOVED ) {
397 gtk_list_store_remove(list, &iter );
398 }
399 }
400 return TRUE;
401 }
403 /**
404 * Set the device popup selection based on the device (works for both primary
405 * and secondary devices)
406 */
407 static void maple_set_device_selection( GtkWidget *combo, maple_device_t device )
408 {
409 GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
410 GtkTreeIter iter;
412 if( device == NULL ) {
413 gtk_combo_box_set_active( GTK_COMBO_BOX(combo), 0 );
414 return;
415 }
417 gboolean valid = gtk_tree_model_get_iter_first(model, &iter);
418 while( valid ) {
419 const struct maple_device_class *clz;
420 const gchar *vmu_filename;
422 gtk_tree_model_get(model, &iter, 1, &clz, 2, &vmu_filename, -1 );
424 if( device->device_class == clz ) {
425 gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter );
426 return;
427 } else if( vmu_filename != NULL && MAPLE_IS_VMU(device) &&
428 MAPLE_VMU_HAS_NAME(device, vmu_filename) ) {
429 gtk_combo_box_set_active_iter( GTK_COMBO_BOX(combo), &iter );
430 return;
431 }
433 valid = gtk_tree_model_iter_next(model, &iter);
434 }
435 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
436 }
438 static void maple_dialog_done( GtkWidget *panel, gboolean isOK )
439 {
440 void *p = g_object_get_data( G_OBJECT(panel), "subdev_model" );
441 unregister_vmulist_change_hook( maple_vmulist_changed, p );
443 if( isOK ) {
444 int i;
445 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
446 if( maple_data[i].new_device != maple_data[i].old_device ) {
447 if( maple_data[i].old_device != NULL ) {
448 maple_detach_device(MAPLE_DEVID_PORT(i),MAPLE_DEVID_SLOT(i));
449 }
450 if( maple_data[i].new_device != NULL ) {
451 maple_attach_device(maple_data[i].new_device, MAPLE_DEVID_PORT(i), MAPLE_DEVID_SLOT(i) );
452 }
453 }
454 }
455 lxdream_save_config();
456 } else {
457 int i;
458 for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
459 if( maple_data[i].new_device != NULL &&
460 maple_data[i].new_device != maple_data[i].old_device ) {
461 maple_data[i].new_device->destroy(maple_data[i].new_device);
462 }
463 }
464 }
466 }
468 static GtkWidget *maple_panel_new()
469 {
470 GtkWidget *table = gtk_table_new( MAPLE_PORTS * (MAPLE_USER_SLOTS+1), 3, TRUE);
471 int i,j,k;
472 const struct maple_device_class **devices = maple_get_device_classes();
474 gtk_table_set_row_spacings(GTK_TABLE(table), 3);
475 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
477 /* Device models */
478 GtkListStore *dev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
479 maple_build_device_model(dev_model);
481 GtkListStore *subdev_model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
482 maple_build_subdevice_model(subdev_model);
483 g_object_set_data( G_OBJECT(table), "subdev_model", subdev_model );
484 register_vmulist_change_hook( maple_vmulist_changed, subdev_model );
486 int y =0;
487 for( i=0; i< MAPLE_PORTS; i++ ) {
488 char buf[16];
489 GtkWidget *combo, *button;
490 int active = 0, length = 1;
491 maple_device_t device = maple_get_device(i,0);
492 int has_slots = device == NULL ? 0 : MAPLE_SLOTS(device->device_class);
494 snprintf( buf, sizeof(buf), _("Port %c."), 'A'+i );
495 gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(buf), 0, 1, y, y+1 );
497 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(dev_model));
498 GtkCellRenderer *rend = gtk_cell_renderer_text_new();
499 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE);
500 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 );
501 maple_set_device_selection(combo,device);
502 gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 );
504 button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES );
505 gtk_widget_set_sensitive(button, active != 0 && device->get_config != NULL);
506 gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 );
508 maple_data[MAPLE_DEVID(i,0)].old_device = device;
509 maple_data[MAPLE_DEVID(i,0)].new_device = device;
510 maple_data[MAPLE_DEVID(i,0)].combo = combo;
511 maple_data[MAPLE_DEVID(i,0)].button = button;
512 maple_data[MAPLE_DEVID(i,0)].primarySlot = TRUE;
513 g_signal_connect( button, "clicked",
514 G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,0)] );
515 g_signal_connect( combo, "changed",
516 G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,0)] );
517 y++;
519 for( k=0; k< MAPLE_USER_SLOTS; k++ ) {
520 char tmp[32] = " ";
521 device = maple_get_device(i,k+1);
522 active = 0;
523 snprintf( tmp+8, sizeof(tmp)-8, _("VMU %d."), (k+1) );
524 gtk_table_attach_defaults( GTK_TABLE(table), gtk_label_new(tmp), 0, 1, y, y+1 );
525 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(subdev_model));
526 GtkCellRenderer *rend = gtk_cell_renderer_text_new();
527 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(combo), rend, TRUE);
528 gtk_cell_layout_add_attribute( GTK_CELL_LAYOUT(combo), rend, "text", 0 );
529 maple_set_device_selection(combo, device);
531 gtk_table_attach_defaults( GTK_TABLE(table), combo, 1, 2, y, y+1 );
532 button = gtk_button_new_from_stock( GTK_STOCK_PROPERTIES );
533 gtk_table_attach_defaults( GTK_TABLE(table), button, 2, 3, y, y+1 );
534 if( k >= has_slots ) {
535 gtk_widget_set_sensitive(combo, FALSE);
536 gtk_widget_set_sensitive(button, FALSE);
537 } else {
538 gtk_widget_set_sensitive(button, device != NULL && device->get_config != NULL && !MAPLE_IS_VMU(device));
539 }
541 maple_data[MAPLE_DEVID(i,k+1)].old_device = device;
542 maple_data[MAPLE_DEVID(i,k+1)].new_device = device;
543 maple_data[MAPLE_DEVID(i,k+1)].combo = combo;
544 maple_data[MAPLE_DEVID(i,k+1)].button = button;
545 maple_data[MAPLE_DEVID(i,k+1)].primarySlot = FALSE;
546 g_signal_connect( button, "clicked",
547 G_CALLBACK( maple_properties_activated ), &maple_data[MAPLE_DEVID(i,k+1)] );
548 g_signal_connect( combo, "changed",
549 G_CALLBACK( maple_device_changed ), &maple_data[MAPLE_DEVID(i,k+1)] );
550 y++;
551 }
552 gtk_table_set_row_spacing( GTK_TABLE(table), y-1, 10 );
553 }
554 return table;
555 }
557 void maple_dialog_run( )
558 {
559 gtk_gui_run_property_dialog( _("Controller Settings"), maple_panel_new(), maple_dialog_done );
560 }
.