Search
lxdream.org :: lxdream/src/cocoaui/cocoa_ctrl.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/cocoaui/cocoa_ctrl.c
changeset 770:429ff505c450
prev765:4cd066048203
next787:6717c02ff81f
author nkeynes
date Mon Jul 28 03:41:25 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Implement key-binding configuration pane for Cocoa UI
Minor tweaks for consistency and static-correctness
file annotate diff log raw
1.1 --- a/src/cocoaui/cocoa_ctrl.c Wed Jul 23 11:11:30 2008 +0000
1.2 +++ b/src/cocoaui/cocoa_ctrl.c Mon Jul 28 03:41:25 2008 +0000
1.3 @@ -18,10 +18,254 @@
1.4
1.5 #include "cocoaui.h"
1.6 #include "config.h"
1.7 +#include "display.h"
1.8 #include "maple/maple.h"
1.9
1.10 +#include <glib/gstrfuncs.h>
1.11 +
1.12 #define MAX_DEVICES 4
1.13
1.14 +static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
1.15 +
1.16 +@interface KeyBindingEditor (Private)
1.17 +- (void)updateKeysym: (const gchar *)sym;
1.18 +@end
1.19 +
1.20 +@implementation KeyBindingEditor
1.21 +- (id)init
1.22 +{
1.23 + self = [super init];
1.24 + isPrimed = NO;
1.25 + lastValue = nil;
1.26 + [self setFieldEditor: YES];
1.27 + [self setEditable: FALSE];
1.28 + return self;
1.29 +}
1.30 +- (void)dealloc
1.31 +{
1.32 + if( lastValue != nil ) {
1.33 + [lastValue release];
1.34 + lastValue = nil;
1.35 + }
1.36 + [super dealloc];
1.37 +}
1.38 +- (void)setPrimed: (BOOL)primed
1.39 +{
1.40 + if( primed != isPrimed ) {
1.41 + isPrimed = primed;
1.42 + if( primed ) {
1.43 + lastValue = [[NSString stringWithString: [self string]] retain];
1.44 + [self setString: @"<press key>"];
1.45 + input_set_keysym_hook(cocoa_config_keysym_hook, self);
1.46 + } else {
1.47 + [lastValue release];
1.48 + lastValue = nil;
1.49 + input_set_keysym_hook(NULL,NULL);
1.50 + }
1.51 + }
1.52 +}
1.53 +- (void)fireBindingChanged
1.54 +{
1.55 + id delegate = [self delegate];
1.56 + if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
1.57 + [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
1.58 + }
1.59 +}
1.60 +
1.61 +- (void)updateKeysym: (const gchar *)sym
1.62 +{
1.63 + if( sym != NULL ) {
1.64 + [self setString: [NSString stringWithCString: sym]];
1.65 + [self setPrimed: NO];
1.66 + [self fireBindingChanged];
1.67 + }
1.68 +}
1.69 +- (void)keyPressed: (int)keycode
1.70 +{
1.71 + gchar *keysym = input_keycode_to_keysym(NULL, keycode);
1.72 + if( keysym != NULL ) {
1.73 + [self updateKeysym: keysym];
1.74 + g_free(keysym);
1.75 + }
1.76 +}
1.77 +- (void)insertText:(id)string
1.78 +{
1.79 + // Do nothing
1.80 +}
1.81 +- (void)mouseDown: (NSEvent *)event
1.82 +{
1.83 + [self setPrimed: YES];
1.84 + [super mouseDown: event];
1.85 +}
1.86 +- (void)keyDown: (NSEvent *) event
1.87 +{
1.88 + NSString *chars = [event characters];
1.89 + if( isPrimed ) {
1.90 + if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
1.91 + // Escape char = abort change
1.92 + [self setString: lastValue];
1.93 + [self setPrimed: NO];
1.94 + } else {
1.95 + [self keyPressed: ([event keyCode]+1)];
1.96 + }
1.97 + } else {
1.98 + if( chars != NULL && [chars length] == 1 ) {
1.99 + int ch = [chars characterAtIndex: 0];
1.100 + switch( ch ) {
1.101 + case 0x7F:
1.102 + [self setString: @""];
1.103 + [self fireBindingChanged];
1.104 + break;
1.105 + case '\r':
1.106 + [self setPrimed: YES];
1.107 + break;
1.108 + default:
1.109 + [super keyDown: event];
1.110 + break;
1.111 + }
1.112 + } else {
1.113 + [super keyDown: event];
1.114 + }
1.115 + }
1.116 +}
1.117 +- (void)flagsChanged: (NSEvent *) event
1.118 +{
1.119 + if( isPrimed ) {
1.120 + [self keyPressed: ([event keyCode]+1)];
1.121 + }
1.122 + [super flagsChanged: event];
1.123 +}
1.124 +@end
1.125 +
1.126 +static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
1.127 +{
1.128 + KeyBindingEditor *editor = (KeyBindingEditor *)data;
1.129 + [editor updateKeysym: keysym];
1.130 +}
1.131 +
1.132 +
1.133 +@implementation KeyBindingField
1.134 +@end
1.135 +
1.136 +/*************************** Key-binding sub-view ***********************/
1.137 +
1.138 +#define MAX_KEY_BINDINGS 32
1.139 +
1.140 +@interface ControllerKeyBindingView : NSView
1.141 +{
1.142 + maple_device_t device;
1.143 + KeyBindingField *field[MAX_KEY_BINDINGS][2];
1.144 +}
1.145 +- (id)initWithFrame: (NSRect)frameRect;
1.146 +- (void)setDevice: (maple_device_t)device;
1.147 +@end
1.148 +
1.149 +@implementation ControllerKeyBindingView
1.150 +- (id)initWithFrame: (NSRect)frameRect
1.151 +{
1.152 + if( [super initWithFrame: frameRect] == nil ) {
1.153 + return nil;
1.154 + } else {
1.155 + device = NULL;
1.156 + return self;
1.157 + }
1.158 +}
1.159 +- (BOOL)isFlipped
1.160 +{
1.161 + return YES;
1.162 +}
1.163 +- (void)removeSubviews
1.164 +{
1.165 + [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
1.166 +}
1.167 +- (void)controlTextDidChange: (NSNotification *)notify
1.168 +{
1.169 + int binding = [[notify object] tag];
1.170 + NSString *val1 = [field[binding][0] stringValue];
1.171 + NSString *val2 = [field[binding][1] stringValue];
1.172 + char buf[ [val1 length] + [val2 length] + 2 ];
1.173 + const gchar *p = NULL;
1.174 +
1.175 + if( [val1 length] == 0 ) {
1.176 + if( [val2 length] != 0 ) {
1.177 + p = [val2 UTF8String];
1.178 + }
1.179 + } else if( [val2 length] == 0 ) {
1.180 + p = [val1 UTF8String];
1.181 + } else {
1.182 + sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
1.183 + p = buf;
1.184 + }
1.185 + maple_set_device_config_value( device, binding, p );
1.186 + lxdream_save_config();
1.187 +}
1.188 +- (void)setDevice: (maple_device_t)newDevice
1.189 +{
1.190 + device = newDevice;
1.191 + [self removeSubviews];
1.192 + if( device != NULL ) {
1.193 + lxdream_config_entry_t config = maple_get_device_config(device);
1.194 + if( config != NULL ) {
1.195 + int count, i, y, x;
1.196 +
1.197 + for( count=0; config[count].key != NULL; count++ );
1.198 + x = TEXT_GAP;
1.199 + NSSize size = NSMakeSize(85*3+TEXT_GAP*4, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
1.200 + [self setFrameSize: size];
1.201 + [self scrollRectToVisible: NSMakeRect(0,0,1,1)];
1.202 + y = TEXT_GAP;
1.203 + for( i=0; config[i].key != NULL; i++ ) {
1.204 + NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT);
1.205 + NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame);
1.206 + [label setAlignment: NSRightTextAlignment];
1.207 +
1.208 + frame = NSMakeRect( x + 85 + TEXT_GAP, y, 85, TEXT_HEIGHT);
1.209 + field[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
1.210 + [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.211 + [field[i][0] setTag: i];
1.212 + [field[i][0] setDelegate: self];
1.213 + [self addSubview: field[i][0]];
1.214 +
1.215 + frame = NSMakeRect( x + (85*2) + (TEXT_GAP*2), y, 85, TEXT_HEIGHT);
1.216 + field[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
1.217 + [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.218 + [field[i][1] setTag: i];
1.219 + [field[i][1] setDelegate: self];
1.220 + [self addSubview: field[i][1]];
1.221 +
1.222 + if( config[i].value != NULL ) {
1.223 + gchar **parts = g_strsplit(config[i].value,",",3);
1.224 + if( parts[0] != NULL ) {
1.225 + [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
1.226 + if( parts[1] != NULL ) {
1.227 + [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
1.228 + }
1.229 + }
1.230 + g_strfreev(parts);
1.231 + }
1.232 +
1.233 + y += (TEXT_HEIGHT + TEXT_GAP);
1.234 + }
1.235 + } else {
1.236 + [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.237 + }
1.238 + } else {
1.239 + [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.240 + }
1.241 +}
1.242 +@end
1.243 +
1.244 +/*************************** Top-level controller pane ***********************/
1.245 +
1.246 +@interface LxdreamPrefsControllerPane: LxdreamPrefsPane
1.247 +{
1.248 + struct maple_device *save_controller[4];
1.249 + NSButton *radio[4];
1.250 + ControllerKeyBindingView *key_bindings;
1.251 +}
1.252 ++ (LxdreamPrefsControllerPane *)new;
1.253 +@end
1.254 +
1.255 @implementation LxdreamPrefsControllerPane
1.256 + (LxdreamPrefsControllerPane *)new
1.257 {
1.258 @@ -35,19 +279,46 @@
1.259 const struct maple_device_class **devices = maple_get_device_classes();
1.260 char buf[16];
1.261 int i,j;
1.262 - int height = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
1.263 + int y = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
1.264 +
1.265 + NSBox *rule = [[NSBox alloc] initWithFrame:
1.266 + NSMakeRect(210+(TEXT_GAP*3), 1, 1, [self contentHeight] + TEXT_GAP - 2)];
1.267 + [rule setAutoresizingMask: (NSViewMaxXMargin|NSViewHeightSizable)];
1.268 + [rule setBoxType: NSBoxSeparator];
1.269 + [self addSubview: rule];
1.270 +
1.271 + NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
1.272 + frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
1.273 + NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
1.274 + key_bindings = [[ControllerKeyBindingView alloc] initWithFrame: bindingFrame ];
1.275 + [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
1.276 + [scrollView setDocumentView: key_bindings];
1.277 + [scrollView setDrawsBackground: NO];
1.278 + [scrollView setHasVerticalScroller: YES];
1.279 + [scrollView setAutohidesScrollers: YES];
1.280 +
1.281 + [self addSubview: scrollView];
1.282 + [key_bindings setDevice: maple_get_device(0,0)];
1.283 +
1.284 for( i=0; i<MAX_DEVICES; i++ ) {
1.285 + int x = TEXT_GAP;
1.286 save_controller[i] = NULL;
1.287 maple_device_t device = maple_get_device(i,0);
1.288 - NSRect frame = NSMakeRect( TEXT_GAP, height -((TEXT_HEIGHT+TEXT_GAP)*i - 2),
1.289 - 50, LABEL_HEIGHT );
1.290 +
1.291 snprintf( buf, sizeof(buf), _("Slot %d."), i );
1.292 - NSTextField *label = [self addLabel: [NSString stringWithUTF8String: buf]
1.293 - withFrame: frame ];
1.294 - [label setAlignment: NSRightTextAlignment];
1.295 - frame = NSMakeRect( 50 + (TEXT_GAP*2), height - ((TEXT_HEIGHT+TEXT_GAP)*i),
1.296 - 150, TEXT_HEIGHT );
1.297 - NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: frame pullsDown: NO];
1.298 + radio[i] = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )];
1.299 + [radio[i] setTitle: [NSString stringWithUTF8String: buf]];
1.300 + [radio[i] setTag: i];
1.301 + [radio[i] setButtonType: NSRadioButton];
1.302 + [radio[i] setAlignment: NSRightTextAlignment];
1.303 + [radio[i] setTarget: self];
1.304 + [radio[i] setAction: @selector(radioChanged:)];
1.305 + [radio[i] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.306 + [self addSubview: radio[i]];
1.307 + x += 60 + TEXT_GAP;
1.308 +
1.309 + NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: NSMakeRect(x,y,150,TEXT_HEIGHT)
1.310 + pullsDown: NO];
1.311 [popup addItemWithTitle: NS_("<empty>")];
1.312 [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.313 [[popup itemAtIndex: 0] setTag: 0];
1.314 @@ -62,16 +333,38 @@
1.315 [popup setAction: @selector(deviceChanged:)];
1.316 [popup setTag: i];
1.317 [self addSubview: popup];
1.318 + y -= (TEXT_HEIGHT+TEXT_GAP);
1.319 }
1.320 +
1.321 + [radio[0] setState: NSOnState];
1.322 return self;
1.323 }
1.324 }
1.325 +- (void)radioChanged: (id)sender
1.326 +{
1.327 + int slot = [sender tag];
1.328 + int i;
1.329 + for( i=0; i<MAX_DEVICES; i++ ) {
1.330 + if( i != slot ) {
1.331 + [radio[i] setState: NSOffState];
1.332 + }
1.333 + }
1.334 + [key_bindings setDevice: maple_get_device(slot,0)];
1.335 +}
1.336 - (void)deviceChanged: (id)sender
1.337 {
1.338 int slot = [sender tag];
1.339 - int new_device_idx = [sender indexOfSelectedItem] - 1;
1.340 + int new_device_idx = [sender indexOfSelectedItem] - 1, i;
1.341 maple_device_class_t new_device_class = NULL;
1.342
1.343 + for( i=0; i<MAX_DEVICES; i++ ) {
1.344 + if( i == slot ) {
1.345 + [radio[i] setState: NSOnState];
1.346 + } else {
1.347 + [radio[i] setState: NSOffState];
1.348 + }
1.349 + }
1.350 +
1.351 maple_device_t current = maple_get_device(slot,0);
1.352 maple_device_t new_device = NULL;
1.353 if( new_device_idx != -1 ) {
1.354 @@ -79,6 +372,7 @@
1.355 }
1.356 if( current == NULL ? new_device_class == NULL : current->device_class == new_device_class ) {
1.357 // No change
1.358 + [key_bindings setDevice: current];
1.359 return;
1.360 }
1.361 if( current != NULL && current->device_class == &controller_class ) {
1.362 @@ -95,7 +389,12 @@
1.363 }
1.364 maple_attach_device(new_device,slot,0);
1.365 }
1.366 -
1.367 + [key_bindings setDevice: maple_get_device(slot,0)];
1.368 lxdream_save_config();
1.369 }
1.370 @end
1.371 +
1.372 +NSView *cocoa_gui_create_prefs_controller_pane()
1.373 +{
1.374 + return [LxdreamPrefsControllerPane new];
1.375 +}
.