Search
lxdream.org :: lxdream/src/cocoaui/cocoa_ctrl.m
lxdream 0.9.1
released Jun 29
Download Now
filename src/cocoaui/cocoa_ctrl.m
changeset 1298:d0eb2307b847
prev1297:7e98a164b2d9
author nkeynes
date Wed Feb 04 08:38:23 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix assorted compile warnings reported by Clang
file annotate diff log raw
nkeynes@964
     1
/**
nkeynes@964
     2
 * $Id$
nkeynes@964
     3
 *
nkeynes@964
     4
 * Construct and manage the controller configuration pane
nkeynes@964
     5
 *
nkeynes@964
     6
 * Copyright (c) 2008 Nathan Keynes.
nkeynes@964
     7
 *
nkeynes@964
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@964
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@964
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@964
    11
 * (at your option) any later version.
nkeynes@964
    12
 *
nkeynes@964
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@964
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@964
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@964
    16
 * GNU General Public License for more details.
nkeynes@964
    17
 */
nkeynes@964
    18
nkeynes@964
    19
#include "cocoaui.h"
nkeynes@964
    20
#include "config.h"
nkeynes@1041
    21
#include "lxpaths.h"
nkeynes@964
    22
#include "display.h"
nkeynes@964
    23
#include "maple/maple.h"
nkeynes@1034
    24
#include "vmu/vmulist.h"
nkeynes@964
    25
nkeynes@1297
    26
#include <glib.h>
nkeynes@964
    27
nkeynes@1034
    28
#define FIRST_SECONDARY_DEVICE MAPLE_PORTS
nkeynes@1034
    29
nkeynes@1034
    30
#define FIRST_VMU_TAG 0x1000
nkeynes@1034
    31
#define LOAD_VMU_TAG -1
nkeynes@1034
    32
#define CREATE_VMU_TAG -2
nkeynes@964
    33
nkeynes@1072
    34
#define LABEL_WIDTH 85
nkeynes@964
    35
nkeynes@1072
    36
nkeynes@1034
    37
static gboolean cocoa_config_vmulist_hook(vmulist_change_type_t type, int idx, void *data);
nkeynes@964
    38
/*************************** Top-level controller pane ***********************/
nkeynes@1034
    39
static NSButton *addRadioButton( int port, int sub, int x, int y, id parent )
nkeynes@1034
    40
{
nkeynes@1034
    41
    char buf[16];
nkeynes@1034
    42
    
nkeynes@1034
    43
    if( sub == 0 ) {
nkeynes@1034
    44
        snprintf( buf, sizeof(buf), _("Port %c."), 'A'+port );
nkeynes@1034
    45
    } else {
nkeynes@1034
    46
        snprintf( buf, sizeof(buf), _("VMU %d."), sub );
nkeynes@1034
    47
    }
nkeynes@1034
    48
nkeynes@1034
    49
    NSButton *radio = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )];
nkeynes@1034
    50
    [radio setTitle: [NSString stringWithUTF8String: buf]];
nkeynes@1034
    51
    [radio setTag: MAPLE_DEVID(port,sub) ];
nkeynes@1034
    52
    [radio setButtonType: NSRadioButton];
nkeynes@1034
    53
    [radio setAlignment: NSRightTextAlignment];
nkeynes@1034
    54
    [radio setTarget: parent];
nkeynes@1034
    55
    [radio setAction: @selector(radioChanged:)];
nkeynes@1034
    56
    [radio setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
nkeynes@1034
    57
    [parent addSubview: radio];
nkeynes@1034
    58
    return radio;
nkeynes@1034
    59
}
nkeynes@1034
    60
nkeynes@1034
    61
static void setDevicePopupSelection( NSPopUpButton *popup, maple_device_t device )
nkeynes@1034
    62
{
nkeynes@1034
    63
    if( device == NULL ) {
nkeynes@1034
    64
        [popup selectItemAtIndex: 0];
nkeynes@1034
    65
    } else if( MAPLE_IS_VMU(device) ) {
nkeynes@1034
    66
        int idx = vmulist_get_index_by_filename( MAPLE_VMU_NAME(device) );
nkeynes@1034
    67
        if( idx == -1 ) {
nkeynes@1034
    68
            [popup selectItemAtIndex: 0];
nkeynes@1034
    69
        } else {
nkeynes@1034
    70
            [popup selectItemWithTag: FIRST_VMU_TAG + idx];
nkeynes@1034
    71
        }
nkeynes@1034
    72
    } else {
nkeynes@1034
    73
        const struct maple_device_class **devices = maple_get_device_classes();
nkeynes@1034
    74
        int i;
nkeynes@1034
    75
        for( i=0; devices[i] != NULL; i++ ) {
nkeynes@1034
    76
            if( devices[i] == device->device_class ) {
nkeynes@1034
    77
                [popup selectItemWithTag: i+1];
nkeynes@1034
    78
                return;
nkeynes@1034
    79
            }
nkeynes@1034
    80
        }
nkeynes@1034
    81
        // Should never get here, but if so...
nkeynes@1034
    82
        [popup selectItemAtIndex: 0];
nkeynes@1034
    83
    }
nkeynes@1034
    84
}
nkeynes@1034
    85
nkeynes@1034
    86
static void buildDevicePopupMenu( NSPopUpButton *popup, maple_device_t device, BOOL primary )
nkeynes@1034
    87
{
nkeynes@1034
    88
    int j;
nkeynes@1034
    89
    const struct maple_device_class **devices = maple_get_device_classes();
nkeynes@1034
    90
nkeynes@1034
    91
    [popup removeAllItems];
nkeynes@1034
    92
    [popup addItemWithTitle: NS_("<empty>")];
nkeynes@1034
    93
    [[popup itemAtIndex: 0] setTag: 0];
nkeynes@1034
    94
    for( j=0; devices[j] != NULL; j++ ) {
nkeynes@1034
    95
        int isPrimaryDevice = devices[j]->flags & MAPLE_TYPE_PRIMARY;
nkeynes@1034
    96
        if( primary ? isPrimaryDevice : (!isPrimaryDevice && !MAPLE_IS_VMU_CLASS(devices[j])) ) {
nkeynes@1034
    97
            [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]];
nkeynes@1034
    98
            if( device != NULL && device->device_class == devices[j] ) {
nkeynes@1034
    99
                [popup selectItemAtIndex: ([popup numberOfItems]-1)];
nkeynes@1034
   100
            }
nkeynes@1034
   101
            [[popup itemAtIndex: ([popup numberOfItems]-1)] setTag: (j+1)];
nkeynes@1034
   102
        }
nkeynes@1034
   103
    }
nkeynes@1034
   104
    
nkeynes@1034
   105
    if( !primary ) {
nkeynes@1034
   106
        BOOL vmu_selected = NO;
nkeynes@1072
   107
        const char *vmu_name = NULL;
nkeynes@1034
   108
        if( device != NULL && MAPLE_IS_VMU(device) ) {
nkeynes@1034
   109
            vmu_name = MAPLE_VMU_NAME(device);
nkeynes@1072
   110
            if( vmu_name == NULL ) {
nkeynes@1072
   111
                device = NULL;
nkeynes@1072
   112
            } else {
nkeynes@1072
   113
                vmu_selected = YES;
nkeynes@1072
   114
            }
nkeynes@1034
   115
        }
nkeynes@1034
   116
        if( [popup numberOfItems] > 0 ) {
nkeynes@1034
   117
            [[popup menu] addItem: [NSMenuItem separatorItem]];
nkeynes@1034
   118
        }
nkeynes@1034
   119
        
nkeynes@1034
   120
        unsigned int vmu_count = vmulist_get_size();
nkeynes@1034
   121
        for( j=0; j<vmu_count; j++ ) {
nkeynes@1034
   122
            const char *name = vmulist_get_name(j);
nkeynes@1034
   123
            [popup addItemWithTitle: [NSString stringWithUTF8String: name]];
nkeynes@1034
   124
            if( vmu_selected && strcmp(vmu_name, vmulist_get_filename(j)) == 0 ) {
nkeynes@1034
   125
                [popup selectItemAtIndex: ([popup numberOfItems]-1)];
nkeynes@1034
   126
            }
nkeynes@1034
   127
            [[popup itemAtIndex: ([popup numberOfItems]-1)] setTag: FIRST_VMU_TAG + j];
nkeynes@1034
   128
        }
nkeynes@1034
   129
        
nkeynes@1034
   130
        [popup addItemWithTitle: NS_("Load VMU...")];
nkeynes@1034
   131
        [[popup itemAtIndex: ([popup numberOfItems]-1)] setTag: LOAD_VMU_TAG];
nkeynes@1034
   132
        [popup addItemWithTitle: NS_("Create VMU...")];
nkeynes@1034
   133
        [[popup itemAtIndex: ([popup numberOfItems]-1)] setTag: CREATE_VMU_TAG];
nkeynes@1034
   134
    }
nkeynes@1034
   135
    
nkeynes@1034
   136
}
nkeynes@1034
   137
nkeynes@1034
   138
static NSPopUpButton *addDevicePopup( int port, int sub, int x, int y, maple_device_t device, BOOL primary, id parent )
nkeynes@1034
   139
{
nkeynes@1034
   140
    NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: NSMakeRect(x,y,150,TEXT_HEIGHT) 
nkeynes@1034
   141
                                                  pullsDown: NO];
nkeynes@1034
   142
    [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
nkeynes@1034
   143
    buildDevicePopupMenu(popup,device,primary);
nkeynes@1034
   144
nkeynes@1034
   145
    [popup setTarget: parent];
nkeynes@1034
   146
    [popup setAction: @selector(deviceChanged:)];
nkeynes@1034
   147
    [popup setTag: MAPLE_DEVID(port,sub) ];
nkeynes@1034
   148
    [parent addSubview: popup];    
nkeynes@1034
   149
    return popup;
nkeynes@1034
   150
}
nkeynes@1034
   151
nkeynes@1034
   152
@interface VMULoadValidator : NSObject
nkeynes@1034
   153
{
nkeynes@1034
   154
}
nkeynes@1034
   155
- (BOOL)panel:(id) sender isValidFilename: (NSString *)filename;
nkeynes@1034
   156
@end
nkeynes@1034
   157
nkeynes@1034
   158
@implementation VMULoadValidator 
nkeynes@1034
   159
- (BOOL)panel:(id) sender isValidFilename: (NSString *)filename
nkeynes@1034
   160
{
nkeynes@1034
   161
    const char *c_fn = [filename UTF8String];
nkeynes@1034
   162
    vmu_volume_t vol = vmu_volume_load( c_fn );
nkeynes@1034
   163
    if( vol != NULL ) {
nkeynes@1034
   164
        vmulist_add_vmu(c_fn, vol);
nkeynes@1034
   165
        return YES;
nkeynes@1034
   166
    } else {
nkeynes@1034
   167
        ERROR( "Unable to load VMU file (not a valid VMU)" );
nkeynes@1034
   168
        return NO;
nkeynes@1034
   169
    }
nkeynes@1034
   170
}
nkeynes@1034
   171
nkeynes@1034
   172
@end
nkeynes@1034
   173
nkeynes@1034
   174
@interface VMUCreateValidator : NSObject
nkeynes@1034
   175
{
nkeynes@1034
   176
}
nkeynes@1034
   177
- (BOOL)panel:(id) sender isValidFilename: (NSString *)filename;
nkeynes@1034
   178
@end
nkeynes@1034
   179
nkeynes@1034
   180
@implementation VMUCreateValidator 
nkeynes@1034
   181
- (BOOL)panel:(id) sender isValidFilename: (NSString *)filename
nkeynes@1034
   182
{
nkeynes@1034
   183
    const char *vmu_filename = [filename UTF8String];
nkeynes@1034
   184
    int idx = vmulist_create_vmu(vmu_filename, FALSE);
nkeynes@1034
   185
    if( idx == -1 ) {
nkeynes@1034
   186
        ERROR( "Unable to create file: %s\n", strerror(errno) );
nkeynes@1034
   187
        return NO;
nkeynes@1034
   188
    } else {
nkeynes@1034
   189
        return YES;
nkeynes@1034
   190
    }
nkeynes@1034
   191
}
nkeynes@1034
   192
@end
nkeynes@1034
   193
nkeynes@964
   194
nkeynes@964
   195
@interface LxdreamPrefsControllerPane: LxdreamPrefsPane
nkeynes@964
   196
{
nkeynes@1034
   197
    struct maple_device *save_controller[MAPLE_MAX_DEVICES];
nkeynes@1034
   198
    NSButton *radio[MAPLE_MAX_DEVICES];
nkeynes@1034
   199
    NSPopUpButton *popup[MAPLE_MAX_DEVICES];
nkeynes@1072
   200
    ConfigurationView *key_bindings;
nkeynes@964
   201
}
nkeynes@964
   202
+ (LxdreamPrefsControllerPane *)new;
nkeynes@1034
   203
- (void)vmulistChanged: (id)sender;
nkeynes@964
   204
@end
nkeynes@964
   205
nkeynes@1034
   206
static gboolean cocoa_config_vmulist_hook(vmulist_change_type_t type, int idx, void *data)
nkeynes@1034
   207
{
nkeynes@1034
   208
    LxdreamPrefsControllerPane *pane = (LxdreamPrefsControllerPane *)data;
nkeynes@1034
   209
    [pane vmulistChanged: nil];
nkeynes@1034
   210
    return TRUE;
nkeynes@1034
   211
}
nkeynes@1034
   212
nkeynes@964
   213
@implementation LxdreamPrefsControllerPane
nkeynes@964
   214
+ (LxdreamPrefsControllerPane *)new
nkeynes@964
   215
{
nkeynes@964
   216
    return [[LxdreamPrefsControllerPane alloc] initWithFrame: NSMakeRect(0,0,600,400)];
nkeynes@964
   217
}
nkeynes@964
   218
- (id)initWithFrame: (NSRect)frameRect
nkeynes@964
   219
{
nkeynes@964
   220
    if( [super initWithFrame: frameRect title: NS_("Controllers")] == nil ) {
nkeynes@964
   221
        return nil;
nkeynes@964
   222
    } else {
nkeynes@1298
   223
        int i;
nkeynes@964
   224
        int y = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
nkeynes@964
   225
nkeynes@1034
   226
        memset( radio, 0, sizeof(radio) );
nkeynes@1034
   227
        memset( save_controller, 0, sizeof(save_controller) );
nkeynes@964
   228
        NSBox *rule = [[NSBox alloc] initWithFrame: 
nkeynes@964
   229
                NSMakeRect(210+(TEXT_GAP*3), 1, 1, [self contentHeight] + TEXT_GAP - 2)];
nkeynes@964
   230
        [rule setAutoresizingMask: (NSViewMaxXMargin|NSViewHeightSizable)];
nkeynes@964
   231
        [rule setBoxType: NSBoxSeparator];
nkeynes@964
   232
        [self addSubview: rule];
nkeynes@964
   233
        
nkeynes@964
   234
        NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
nkeynes@964
   235
                   frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
nkeynes@964
   236
        NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
nkeynes@1072
   237
        key_bindings = [[ConfigurationView alloc] initWithFrame: bindingFrame ];
nkeynes@1072
   238
        [key_bindings setLabelWidth: LABEL_WIDTH];
nkeynes@964
   239
        [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
nkeynes@964
   240
        [scrollView setDocumentView: key_bindings];
nkeynes@964
   241
        [scrollView setDrawsBackground: NO];
nkeynes@964
   242
        [scrollView setHasVerticalScroller: YES];
nkeynes@964
   243
        [scrollView setAutohidesScrollers: YES];
nkeynes@964
   244
 
nkeynes@964
   245
        [self addSubview: scrollView];
nkeynes@964
   246
        [key_bindings setDevice: maple_get_device(0,0)];
nkeynes@964
   247
        
nkeynes@1034
   248
        for( i=0; i<MAPLE_PORTS; i++ ) {
nkeynes@964
   249
            maple_device_t device = maple_get_device(i,0);
nkeynes@964
   250
nkeynes@1034
   251
            radio[i] = addRadioButton(i,0,TEXT_GAP,y,self);
nkeynes@1034
   252
            popup[i] = addDevicePopup(i,0,60 + (TEXT_GAP*2),y,device, YES,self);
nkeynes@1034
   253
            y -= (TEXT_HEIGHT+TEXT_GAP);
nkeynes@1034
   254
            
nkeynes@1034
   255
            int j,max = device == NULL ? 0 : MAPLE_SLOTS(device->device_class);
nkeynes@1034
   256
            for( j=1; j<=MAPLE_USER_SLOTS; j++ ) {
nkeynes@1034
   257
                radio[MAPLE_DEVID(i,j)] = addRadioButton(i, j, TEXT_GAP*2, y, self);
nkeynes@1034
   258
                popup[MAPLE_DEVID(i,j)] = addDevicePopup(i, j, 60 + TEXT_GAP*2, y, maple_get_device(i,j), NO, self);
nkeynes@1034
   259
                y -= (TEXT_HEIGHT+TEXT_GAP);
nkeynes@1034
   260
                if( j > max ) {
nkeynes@1034
   261
                    [radio[MAPLE_DEVID(i,j)] setEnabled: NO];
nkeynes@1034
   262
                    [popup[MAPLE_DEVID(i,j)] setEnabled: NO];
nkeynes@964
   263
                }
nkeynes@964
   264
            }
nkeynes@964
   265
        }
nkeynes@964
   266
        
nkeynes@964
   267
        [radio[0] setState: NSOnState];
nkeynes@1034
   268
        
nkeynes@1034
   269
        register_vmulist_change_hook(cocoa_config_vmulist_hook, self);
nkeynes@964
   270
        return self;
nkeynes@964
   271
    }
nkeynes@964
   272
}
nkeynes@1034
   273
- (void)dealloc
nkeynes@1034
   274
{
nkeynes@1034
   275
    unregister_vmulist_change_hook(cocoa_config_vmulist_hook,self);
nkeynes@1034
   276
    [super dealloc];
nkeynes@1034
   277
}
nkeynes@1034
   278
- (void)vmulistChanged: (id)sender
nkeynes@1034
   279
{
nkeynes@1034
   280
    int i;
nkeynes@1034
   281
    for( i=FIRST_SECONDARY_DEVICE; i<MAPLE_MAX_DEVICES; i++ ) {
nkeynes@1034
   282
        if( popup[i] != NULL ) {
nkeynes@1034
   283
            buildDevicePopupMenu(popup[i], maple_get_device(MAPLE_DEVID_PORT(i), MAPLE_DEVID_SLOT(i)), NO );
nkeynes@1034
   284
        }
nkeynes@1034
   285
    }
nkeynes@1034
   286
}
nkeynes@964
   287
- (void)radioChanged: (id)sender
nkeynes@964
   288
{
nkeynes@1034
   289
    int tag = [sender tag];
nkeynes@964
   290
    int i;
nkeynes@1034
   291
    for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
nkeynes@1034
   292
        if( i != tag && radio[i] != NULL ) {
nkeynes@964
   293
            [radio[i] setState: NSOffState];
nkeynes@964
   294
        }
nkeynes@964
   295
    }
nkeynes@1034
   296
    [key_bindings setDevice: maple_get_device(MAPLE_DEVID_PORT(tag),MAPLE_DEVID_SLOT(tag))];
nkeynes@964
   297
}
nkeynes@964
   298
- (void)deviceChanged: (id)sender
nkeynes@964
   299
{
nkeynes@1034
   300
    int tag = [sender tag];
nkeynes@1034
   301
    int port = MAPLE_DEVID_PORT(tag);
nkeynes@1034
   302
    int slot = MAPLE_DEVID_SLOT(tag);
nkeynes@1034
   303
    int new_device_idx = [[sender selectedItem] tag], i; 
nkeynes@964
   304
    maple_device_class_t new_device_class = NULL;
nkeynes@1034
   305
    const gchar *vmu_filename = NULL;
nkeynes@964
   306
    
nkeynes@1034
   307
    for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
nkeynes@1034
   308
        if( radio[i] != NULL ) {
nkeynes@1034
   309
            if( i == tag ) {
nkeynes@1034
   310
                [radio[i] setState: NSOnState];
nkeynes@1034
   311
            } else {
nkeynes@1034
   312
                [radio[i] setState: NSOffState];
nkeynes@1034
   313
            }
nkeynes@964
   314
        }
nkeynes@964
   315
    }
nkeynes@964
   316
    
nkeynes@1034
   317
    maple_device_t current = maple_get_device(port,slot);
nkeynes@964
   318
    maple_device_t new_device = NULL;
nkeynes@1034
   319
    if( new_device_idx == LOAD_VMU_TAG ) {
nkeynes@1034
   320
        NSArray *array = [NSArray arrayWithObjects: @"vmu", nil];
nkeynes@1034
   321
        NSOpenPanel *panel = [NSOpenPanel openPanel];
nkeynes@1034
   322
        VMULoadValidator *valid = [[VMULoadValidator alloc] autorelease];
nkeynes@1298
   323
        [panel setDelegate: (id)valid];
nkeynes@1058
   324
        int result = [panel runModalForDirectory: [NSString stringWithUTF8String: get_gui_path(CONFIG_VMU_PATH)]
nkeynes@1034
   325
               file: nil types: array];
nkeynes@1034
   326
        if( result == NSOKButton ) {
nkeynes@1034
   327
            vmu_filename = [[panel filename] UTF8String];
nkeynes@1034
   328
            int idx = vmulist_get_index_by_filename(vmu_filename);
nkeynes@1034
   329
            [sender selectItemWithTag: (FIRST_VMU_TAG+idx)];
nkeynes@1034
   330
            new_device_class = &vmu_class;
nkeynes@1041
   331
            set_gui_path(CONFIG_VMU_PATH, [[panel directory] UTF8String]);
nkeynes@1034
   332
        } else {
nkeynes@1034
   333
            /* Cancelled - restore previous value */
nkeynes@1034
   334
            setDevicePopupSelection( sender, current );
nkeynes@1034
   335
            return;
nkeynes@1034
   336
        }
nkeynes@1034
   337
    } else if( new_device_idx == CREATE_VMU_TAG ) {
nkeynes@1034
   338
        NSSavePanel *panel = [NSSavePanel savePanel];
nkeynes@1034
   339
        [panel setTitle: NS_("Create VMU")];
nkeynes@1034
   340
        [panel setCanCreateDirectories: YES];
nkeynes@1034
   341
        [panel setRequiredFileType: @"vmu"];
nkeynes@1034
   342
        VMUCreateValidator *valid = [[VMUCreateValidator alloc] autorelease];
nkeynes@1298
   343
        [panel setDelegate: (id)valid];
nkeynes@1058
   344
        int result = [panel runModalForDirectory: [NSString stringWithUTF8String: get_gui_path(CONFIG_VMU_PATH)]
nkeynes@1034
   345
               file: nil];
nkeynes@1034
   346
        if( result == NSFileHandlingPanelOKButton ) {
nkeynes@1034
   347
            /* Validator has already created the file by now */
nkeynes@1034
   348
            vmu_filename = [[panel filename] UTF8String];
nkeynes@1034
   349
            int idx = vmulist_get_index_by_filename(vmu_filename);
nkeynes@1034
   350
            [sender selectItemWithTag: (FIRST_VMU_TAG+idx)];
nkeynes@1034
   351
            new_device_class = &vmu_class;
nkeynes@1041
   352
            set_gui_path(CONFIG_VMU_PATH, [[panel directory] UTF8String]);
nkeynes@1034
   353
        } else {
nkeynes@1034
   354
            setDevicePopupSelection( sender, current );
nkeynes@1034
   355
            return;
nkeynes@1034
   356
        }
nkeynes@1034
   357
    } else if( new_device_idx >= FIRST_VMU_TAG ) {
nkeynes@1034
   358
        vmu_filename = vmulist_get_filename( new_device_idx - FIRST_VMU_TAG );
nkeynes@1034
   359
        new_device_class = &vmu_class;
nkeynes@1034
   360
    } else if( new_device_idx > 0) {
nkeynes@1034
   361
        new_device_class = maple_get_device_classes()[new_device_idx-1];
nkeynes@964
   362
    }
nkeynes@1034
   363
    
nkeynes@1034
   364
    if( current == NULL ? new_device_class == NULL : 
nkeynes@1034
   365
        (current->device_class == new_device_class && 
nkeynes@1034
   366
                (!MAPLE_IS_VMU(current) || MAPLE_VMU_HAS_NAME(current, vmu_filename))) ) {
nkeynes@964
   367
        // No change
nkeynes@964
   368
        [key_bindings setDevice: current];
nkeynes@964
   369
        return;
nkeynes@964
   370
    }
nkeynes@964
   371
    if( current != NULL && current->device_class == &controller_class ) {
nkeynes@1034
   372
        save_controller[tag] = current->clone(current);
nkeynes@964
   373
    }
nkeynes@964
   374
    if( new_device_class == NULL ) {
nkeynes@1034
   375
        maple_detach_device(port,slot);
nkeynes@1043
   376
        if( slot == 0 ) {
nkeynes@1043
   377
            /* If we detached the top-level dev, any children are automatically detached */
nkeynes@1043
   378
            for( i=1; i<=MAPLE_USER_SLOTS; i++ ) {
nkeynes@1043
   379
                [popup[MAPLE_DEVID(port,i)] selectItemWithTag: 0];
nkeynes@1043
   380
            }
nkeynes@1043
   381
        }
nkeynes@964
   382
    } else {
nkeynes@1034
   383
        if( new_device_class == &controller_class && save_controller[tag] != NULL ) {
nkeynes@1034
   384
            new_device = save_controller[tag];
nkeynes@1034
   385
            save_controller[tag] = NULL;
nkeynes@964
   386
        } else {
nkeynes@964
   387
            new_device = maple_new_device( new_device_class->name );
nkeynes@964
   388
        }
nkeynes@1034
   389
        if( MAPLE_IS_VMU(new_device) ) {
nkeynes@1043
   390
            /* Remove the VMU from any other attachment point */
nkeynes@1043
   391
            for( i=0; i<MAPLE_MAX_DEVICES; i++ ) {
nkeynes@1043
   392
                maple_device_t dev = maple_get_device(MAPLE_DEVID_PORT(i),MAPLE_DEVID_SLOT(i));
nkeynes@1043
   393
                if( dev != NULL && MAPLE_IS_VMU(dev) && MAPLE_VMU_HAS_NAME(dev,vmu_filename) ) {
nkeynes@1043
   394
                    maple_detach_device(MAPLE_DEVID_PORT(i),MAPLE_DEVID_SLOT(i));
nkeynes@1043
   395
                    [popup[i] selectItemWithTag: 0];
nkeynes@1043
   396
                }
nkeynes@1043
   397
            }
nkeynes@1034
   398
            MAPLE_SET_VMU_NAME(new_device,vmu_filename);
nkeynes@1034
   399
        }
nkeynes@1034
   400
        maple_attach_device(new_device,port,slot);
nkeynes@964
   401
    }
nkeynes@1034
   402
    [key_bindings setDevice: maple_get_device(port,slot)];
nkeynes@1034
   403
    
nkeynes@1034
   404
    if( slot == 0 ) { /* Change primary */
nkeynes@1034
   405
        int max = new_device_class == NULL ? 0 : MAPLE_SLOTS(new_device_class);
nkeynes@1034
   406
        for( i=1; i<=MAPLE_USER_SLOTS; i++ ) {
nkeynes@1034
   407
            if( i <= max ) {
nkeynes@1034
   408
                [radio[MAPLE_DEVID(port,i)] setEnabled: YES];
nkeynes@1034
   409
                [popup[MAPLE_DEVID(port,i)] setEnabled: YES];
nkeynes@1034
   410
            } else {
nkeynes@1034
   411
                [radio[MAPLE_DEVID(port,i)] setEnabled: NO];
nkeynes@1034
   412
                [popup[MAPLE_DEVID(port,i)] setEnabled: NO];
nkeynes@1034
   413
            }                
nkeynes@1034
   414
        }
nkeynes@1034
   415
    }
nkeynes@964
   416
    lxdream_save_config();
nkeynes@964
   417
}
nkeynes@964
   418
@end
nkeynes@964
   419
nkeynes@964
   420
NSView *cocoa_gui_create_prefs_controller_pane()
nkeynes@964
   421
{
nkeynes@964
   422
    return [LxdreamPrefsControllerPane new];
nkeynes@964
   423
}
.