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