Search
lxdream.org :: lxdream/src/cocoaui/cocoa_ctrl.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/cocoaui/cocoa_ctrl.c
changeset 849:bbe26d798fc2
prev787:6717c02ff81f
author nkeynes
date Mon Sep 08 05:13:51 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Refactor mouse event management - button events are now usable for controllers
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * Construct and manage the controller configuration pane
     5  *
     6  * Copyright (c) 2008 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #include "cocoaui.h"
    20 #include "config.h"
    21 #include "display.h"
    22 #include "maple/maple.h"
    24 #include <glib/gstrfuncs.h>
    26 #define MAX_DEVICES 4
    28 #define KEYBINDING_SIZE 110
    30 static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
    32 @interface KeyBindingEditor (Private)
    33 - (void)updateKeysym: (const gchar *)sym;
    34 @end
    36 @implementation KeyBindingEditor
    37 - (id)init
    38 {
    39     self = [super init];
    40     isPrimed = NO;
    41     lastValue = nil;
    42     [self setFieldEditor: YES];
    43     [self setEditable: FALSE];
    44     return self;
    45 }
    46 - (void)dealloc
    47 {
    48     if( lastValue != nil ) {
    49         [lastValue release];
    50         lastValue = nil;
    51     }
    52     [super dealloc];
    53 }
    54 - (void)setPrimed: (BOOL)primed
    55 {
    56     if( primed != isPrimed ) {
    57         isPrimed = primed;
    58         if( primed ) {
    59             lastValue = [[NSString stringWithString: [self string]] retain];
    60             [self setString: @"<press key>"];
    61             input_set_keysym_hook(cocoa_config_keysym_hook, self);            
    62         } else {
    63             [lastValue release];
    64             lastValue = nil;
    65             input_set_keysym_hook(NULL,NULL);
    66         }
    67     }
    68 }
    69 - (void)resignFirstResponder
    70 {
    71     if( isPrimed ) {
    72         [self setString: lastValue];
    73         [self setPrimed: NO];
    74     }
    75     [super resignFirstResponder];
    76 }
    77 - (void)fireBindingChanged
    78 {
    79     id delegate = [self delegate];
    80     if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
    81         [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
    82     }
    83 }
    85 - (void)updateKeysym: (const gchar *)sym
    86 {
    87     if( sym != NULL ) {
    88         [self setString: [NSString stringWithCString: sym]];
    89         [self setPrimed: NO];
    90         [self fireBindingChanged];
    91     }
    92 }
    93 - (void)updateMousesym: (int)button
    94 {
    95     gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, (button+1) );
    96     if( keysym != NULL ) {
    97         [self updateKeysym: keysym ];
    98         g_free(keysym);
    99     }
   100 }
   101 - (void)keyPressed: (int)keycode
   102 {
   103     gchar *keysym = input_keycode_to_keysym(NULL, keycode);
   104     if( keysym != NULL ) {
   105         [self updateKeysym: keysym];
   106         g_free(keysym);
   107     }
   108 }
   109 - (void)insertText:(id)string
   110 {
   111     // Do nothing
   112 }
   113 - (void)mouseDown: (NSEvent *)event
   114 {
   115     if( isPrimed ) {
   116         [self updateMousesym: 0];
   117     } else {
   118         [self setPrimed: YES];
   119         [super mouseDown: event];
   120     }
   121 }
   122 - (void)rightMouseDown: (NSEvent *)event
   123 {
   124     if( isPrimed ) {
   125         [self updateMousesym: 1];
   126     }
   127 }
   128 - (void)otherMouseDown: (NSEvent *)event
   129 {
   130     if( isPrimed ) {
   131         [self updateMousesym: [event buttonNumber]];
   132     }
   133 }
   134 - (void)keyDown: (NSEvent *) event
   135 {
   136     NSString *chars = [event characters];
   137     if( isPrimed ) {
   138         if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
   139             // Escape char = abort change
   140             [self setString: lastValue];
   141             [self setPrimed: NO];
   142         } else {
   143             [self keyPressed: ([event keyCode]+1)];
   144         }
   145     } else {
   146         if( chars != NULL && [chars length] == 1 ) {
   147             int ch = [chars characterAtIndex: 0];
   148             switch( ch ) {
   149             case 0x7F:
   150                 [self setString: @""]; 
   151                 [self fireBindingChanged];
   152                 break;
   153             case '\r':
   154                 [self setPrimed: YES];
   155                 break;
   156             default:
   157                 [super keyDown: event];
   158                 break;
   159             }
   160         } else {
   161             [super keyDown: event];
   162         }
   163     }
   164 }
   165 - (void)flagsChanged: (NSEvent *) event
   166 {
   167     if( isPrimed ) {
   168         [self keyPressed: ([event keyCode]+1)];
   169     }
   170     [super flagsChanged: event];
   171 }
   172 @end
   174 static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
   175 {
   176     KeyBindingEditor *editor = (KeyBindingEditor *)data;
   177     [editor updateKeysym: keysym];
   178 }
   181 @implementation KeyBindingField
   182 @end
   184 /*************************** Key-binding sub-view ***********************/
   186 #define MAX_KEY_BINDINGS 32
   188 @interface ControllerKeyBindingView : NSView
   189 {
   190     maple_device_t device;
   191     KeyBindingField *field[MAX_KEY_BINDINGS][2];
   192 }
   193 - (id)initWithFrame: (NSRect)frameRect;
   194 - (void)setDevice: (maple_device_t)device;
   195 @end
   197 @implementation ControllerKeyBindingView
   198 - (id)initWithFrame: (NSRect)frameRect
   199 {
   200     if( [super initWithFrame: frameRect] == nil ) {
   201         return nil;
   202     } else {
   203         device = NULL;
   204         return self;
   205     }
   206 }
   207 - (BOOL)isFlipped
   208 {
   209     return YES;
   210 }
   211 - (void)removeSubviews
   212 {
   213     [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
   214 }
   215 - (void)controlTextDidChange: (NSNotification *)notify
   216 {
   217     int binding = [[notify object] tag];
   218     NSString *val1 = [field[binding][0] stringValue];
   219     NSString *val2 = [field[binding][1] stringValue];
   220     char buf[ [val1 length] + [val2 length] + 2 ];
   221     const gchar *p = NULL;
   223     if( [val1 length] == 0 ) {
   224         if( [val2 length] != 0 ) {
   225             p = [val2 UTF8String];
   226         }
   227     } else if( [val2 length] == 0 ) {
   228         p = [val1 UTF8String];
   229     } else {
   230         sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
   231         p = buf;
   232     }
   233     maple_set_device_config_value( device, binding, p ); 
   234     lxdream_save_config();
   235 }
   236 - (void)setDevice: (maple_device_t)newDevice
   237 {
   238     device = newDevice;
   239     [self removeSubviews];
   240     if( device != NULL ) {
   241         lxdream_config_entry_t config = maple_get_device_config(device);
   242         if( config != NULL ) {
   243             int count, i, y, x;
   245             for( count=0; config[count].key != NULL; count++ );
   246             x = TEXT_GAP;
   247             NSSize size = NSMakeSize(85+KEYBINDING_SIZE*2+TEXT_GAP*4, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
   248             [self setFrameSize: size];
   249             [self scrollRectToVisible: NSMakeRect(0,0,1,1)]; 
   250             y = TEXT_GAP;
   251             for( i=0; config[i].key != NULL; i++ ) {
   252                 NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT);
   253                 NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame);
   254                 [label setAlignment: NSRightTextAlignment];
   256                 frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT);
   257                 field[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
   258                 [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
   259                 [field[i][0] setTag: i];
   260                 [field[i][0] setDelegate: self];
   261                 [self addSubview: field[i][0]];
   263                 frame = NSMakeRect( x + 85 + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT);
   264                 field[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
   265                 [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
   266                 [field[i][1] setTag: i];
   267                 [field[i][1] setDelegate: self];
   268                 [self addSubview: field[i][1]];
   270                 if( config[i].value != NULL ) {
   271                     gchar **parts = g_strsplit(config[i].value,",",3);
   272                     if( parts[0] != NULL ) {
   273                         [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
   274                         if( parts[1] != NULL ) {
   275                             [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
   276                         }
   277                     }
   278                     g_strfreev(parts);
   279                 }
   281                 y += (TEXT_HEIGHT + TEXT_GAP);
   282             }
   283         } else {
   284             [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
   285         }
   286     } else {
   287         [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
   288     }
   289 }
   290 @end
   292 /*************************** Top-level controller pane ***********************/
   294 @interface LxdreamPrefsControllerPane: LxdreamPrefsPane
   295 {
   296     struct maple_device *save_controller[4];
   297     NSButton *radio[4];
   298     ControllerKeyBindingView *key_bindings;
   299 }
   300 + (LxdreamPrefsControllerPane *)new;
   301 @end
   303 @implementation LxdreamPrefsControllerPane
   304 + (LxdreamPrefsControllerPane *)new
   305 {
   306     return [[LxdreamPrefsControllerPane alloc] initWithFrame: NSMakeRect(0,0,600,400)];
   307 }
   308 - (id)initWithFrame: (NSRect)frameRect
   309 {
   310     if( [super initWithFrame: frameRect title: NS_("Controllers")] == nil ) {
   311         return nil;
   312     } else {
   313         const struct maple_device_class **devices = maple_get_device_classes();
   314         char buf[16];
   315         int i,j;
   316         int y = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
   318         NSBox *rule = [[NSBox alloc] initWithFrame: 
   319                 NSMakeRect(210+(TEXT_GAP*3), 1, 1, [self contentHeight] + TEXT_GAP - 2)];
   320         [rule setAutoresizingMask: (NSViewMaxXMargin|NSViewHeightSizable)];
   321         [rule setBoxType: NSBoxSeparator];
   322         [self addSubview: rule];
   324         NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
   325                    frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
   326         NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
   327         key_bindings = [[ControllerKeyBindingView alloc] initWithFrame: bindingFrame ];
   328         [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
   329         [scrollView setDocumentView: key_bindings];
   330         [scrollView setDrawsBackground: NO];
   331         [scrollView setHasVerticalScroller: YES];
   332         [scrollView setAutohidesScrollers: YES];
   334         [self addSubview: scrollView];
   335         [key_bindings setDevice: maple_get_device(0,0)];
   337         for( i=0; i<MAX_DEVICES; i++ ) {
   338             int x = TEXT_GAP;
   339             save_controller[i] = NULL;
   340             maple_device_t device = maple_get_device(i,0);
   342             snprintf( buf, sizeof(buf), _("Slot %d."), i );
   343             radio[i] = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )];
   344             [radio[i] setTitle: [NSString stringWithUTF8String: buf]];
   345             [radio[i] setTag: i];
   346             [radio[i] setButtonType: NSRadioButton];
   347             [radio[i] setAlignment: NSRightTextAlignment];
   348             [radio[i] setTarget: self];
   349             [radio[i] setAction: @selector(radioChanged:)];
   350             [radio[i] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
   351             [self addSubview: radio[i]];
   352             x += 60 + TEXT_GAP;
   354             NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: NSMakeRect(x,y,150,TEXT_HEIGHT) 
   355                                                           pullsDown: NO];
   356             [popup addItemWithTitle: NS_("<empty>")];
   357             [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
   358             [[popup itemAtIndex: 0] setTag: 0];
   359             for( j=0; devices[j] != NULL; j++ ) {
   360                 [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]];
   361                 if( device != NULL && device->device_class == devices[j] ) {
   362                     [popup selectItemAtIndex: (j+1)];
   363                 }
   364                 [[popup itemAtIndex: (j+1)] setTag: (j+1)];
   365             }
   366             [popup setTarget: self];
   367             [popup setAction: @selector(deviceChanged:)];
   368             [popup setTag: i];
   369             [self addSubview: popup];
   370             y -= (TEXT_HEIGHT+TEXT_GAP);
   371         }
   373         [radio[0] setState: NSOnState];
   374         return self;
   375     }
   376 }
   377 - (void)radioChanged: (id)sender
   378 {
   379     int slot = [sender tag];
   380     int i;
   381     for( i=0; i<MAX_DEVICES; i++ ) {
   382         if( i != slot ) {
   383             [radio[i] setState: NSOffState];
   384         }
   385     }
   386     [key_bindings setDevice: maple_get_device(slot,0)];
   387 }
   388 - (void)deviceChanged: (id)sender
   389 {
   390     int slot = [sender tag];
   391     int new_device_idx = [sender indexOfSelectedItem] - 1, i; 
   392     maple_device_class_t new_device_class = NULL;
   394     for( i=0; i<MAX_DEVICES; i++ ) {
   395         if( i == slot ) {
   396             [radio[i] setState: NSOnState];
   397         } else {
   398             [radio[i] setState: NSOffState];
   399         }
   400     }
   402     maple_device_t current = maple_get_device(slot,0);
   403     maple_device_t new_device = NULL;
   404     if( new_device_idx != -1 ) {
   405         new_device_class = maple_get_device_classes()[new_device_idx];
   406     }
   407     if( current == NULL ? new_device_class == NULL : current->device_class == new_device_class ) {
   408         // No change
   409         [key_bindings setDevice: current];
   410         return;
   411     }
   412     if( current != NULL && current->device_class == &controller_class ) {
   413         save_controller[slot] = current->clone(current);
   414     }
   415     if( new_device_class == NULL ) {
   416         maple_detach_device(slot,0);
   417     } else {
   418         if( new_device_class == &controller_class && save_controller[slot] != NULL ) {
   419             new_device = save_controller[slot];
   420             save_controller[slot] = NULL;
   421         } else {
   422             new_device = maple_new_device( new_device_class->name );
   423         }
   424         maple_attach_device(new_device,slot,0);
   425     }
   426     [key_bindings setDevice: maple_get_device(slot,0)];
   427     lxdream_save_config();
   428 }
   429 @end
   431 NSView *cocoa_gui_create_prefs_controller_pane()
   432 {
   433     return [LxdreamPrefsControllerPane new];
   434 }
.