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 1034:7044e01148f0
prev852:2b4a5e3575b9
next1036:af7b0c5905dd
author nkeynes
date Wed Jun 24 02:41:12 2009 +0000 (14 years ago)
permissions -rw-r--r--
last change Add initial VMU support
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@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
}
.