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