Search
lxdream.org :: lxdream/src/cocoaui/cocoa_ctrl.m :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/cocoaui/cocoa_ctrl.m
changeset 964:f2f3c7612d06
next1034:7044e01148f0
author nkeynes
date Wed Jun 03 11:37:10 2009 +0000 (14 years ago)
permissions -rw-r--r--
last change Add missing svn:keywords property
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/cocoaui/cocoa_ctrl.m Wed Jun 03 11:37:10 2009 +0000
1.3 @@ -0,0 +1,434 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * Construct and manage the controller configuration pane
1.8 + *
1.9 + * Copyright (c) 2008 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include "cocoaui.h"
1.23 +#include "config.h"
1.24 +#include "display.h"
1.25 +#include "maple/maple.h"
1.26 +
1.27 +#include <glib/gstrfuncs.h>
1.28 +
1.29 +#define MAX_DEVICES 4
1.30 +
1.31 +#define KEYBINDING_SIZE 110
1.32 +
1.33 +static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
1.34 +
1.35 +@interface KeyBindingEditor (Private)
1.36 +- (void)updateKeysym: (const gchar *)sym;
1.37 +@end
1.38 +
1.39 +@implementation KeyBindingEditor
1.40 +- (id)init
1.41 +{
1.42 + self = [super init];
1.43 + isPrimed = NO;
1.44 + lastValue = nil;
1.45 + [self setFieldEditor: YES];
1.46 + [self setEditable: FALSE];
1.47 + return self;
1.48 +}
1.49 +- (void)dealloc
1.50 +{
1.51 + if( lastValue != nil ) {
1.52 + [lastValue release];
1.53 + lastValue = nil;
1.54 + }
1.55 + [super dealloc];
1.56 +}
1.57 +- (void)setPrimed: (BOOL)primed
1.58 +{
1.59 + if( primed != isPrimed ) {
1.60 + isPrimed = primed;
1.61 + if( primed ) {
1.62 + lastValue = [[NSString stringWithString: [self string]] retain];
1.63 + [self setString: @"<press key>"];
1.64 + input_set_keysym_hook(cocoa_config_keysym_hook, self);
1.65 + } else {
1.66 + [lastValue release];
1.67 + lastValue = nil;
1.68 + input_set_keysym_hook(NULL,NULL);
1.69 + }
1.70 + }
1.71 +}
1.72 +- (void)resignFirstResponder
1.73 +{
1.74 + if( isPrimed ) {
1.75 + [self setString: lastValue];
1.76 + [self setPrimed: NO];
1.77 + }
1.78 + [super resignFirstResponder];
1.79 +}
1.80 +- (void)fireBindingChanged
1.81 +{
1.82 + id delegate = [self delegate];
1.83 + if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
1.84 + [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
1.85 + }
1.86 +}
1.87 +
1.88 +- (void)updateKeysym: (const gchar *)sym
1.89 +{
1.90 + if( sym != NULL ) {
1.91 + [self setString: [NSString stringWithCString: sym]];
1.92 + [self setPrimed: NO];
1.93 + [self fireBindingChanged];
1.94 + }
1.95 +}
1.96 +- (void)updateMousesym: (int)button
1.97 +{
1.98 + gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, (button+1) );
1.99 + if( keysym != NULL ) {
1.100 + [self updateKeysym: keysym ];
1.101 + g_free(keysym);
1.102 + }
1.103 +}
1.104 +- (void)keyPressed: (int)keycode
1.105 +{
1.106 + gchar *keysym = input_keycode_to_keysym(NULL, keycode);
1.107 + if( keysym != NULL ) {
1.108 + [self updateKeysym: keysym];
1.109 + g_free(keysym);
1.110 + }
1.111 +}
1.112 +- (void)insertText:(id)string
1.113 +{
1.114 + // Do nothing
1.115 +}
1.116 +- (void)mouseDown: (NSEvent *)event
1.117 +{
1.118 + if( isPrimed ) {
1.119 + [self updateMousesym: 0];
1.120 + } else {
1.121 + [self setPrimed: YES];
1.122 + [super mouseDown: event];
1.123 + }
1.124 +}
1.125 +- (void)rightMouseDown: (NSEvent *)event
1.126 +{
1.127 + if( isPrimed ) {
1.128 + [self updateMousesym: 1];
1.129 + }
1.130 +}
1.131 +- (void)otherMouseDown: (NSEvent *)event
1.132 +{
1.133 + if( isPrimed ) {
1.134 + [self updateMousesym: [event buttonNumber]];
1.135 + }
1.136 +}
1.137 +- (void)keyDown: (NSEvent *) event
1.138 +{
1.139 + NSString *chars = [event characters];
1.140 + if( isPrimed ) {
1.141 + if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
1.142 + // Escape char = abort change
1.143 + [self setString: lastValue];
1.144 + [self setPrimed: NO];
1.145 + } else {
1.146 + [self keyPressed: ([event keyCode]+1)];
1.147 + }
1.148 + } else {
1.149 + if( chars != NULL && [chars length] == 1 ) {
1.150 + int ch = [chars characterAtIndex: 0];
1.151 + switch( ch ) {
1.152 + case 0x7F:
1.153 + [self setString: @""];
1.154 + [self fireBindingChanged];
1.155 + break;
1.156 + case '\r':
1.157 + [self setPrimed: YES];
1.158 + break;
1.159 + default:
1.160 + [super keyDown: event];
1.161 + break;
1.162 + }
1.163 + } else {
1.164 + [super keyDown: event];
1.165 + }
1.166 + }
1.167 +}
1.168 +- (void)flagsChanged: (NSEvent *) event
1.169 +{
1.170 + if( isPrimed ) {
1.171 + [self keyPressed: ([event keyCode]+1)];
1.172 + }
1.173 + [super flagsChanged: event];
1.174 +}
1.175 +@end
1.176 +
1.177 +static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
1.178 +{
1.179 + KeyBindingEditor *editor = (KeyBindingEditor *)data;
1.180 + [editor updateKeysym: keysym];
1.181 +}
1.182 +
1.183 +
1.184 +@implementation KeyBindingField
1.185 +@end
1.186 +
1.187 +/*************************** Key-binding sub-view ***********************/
1.188 +
1.189 +#define MAX_KEY_BINDINGS 32
1.190 +
1.191 +@interface ControllerKeyBindingView : NSView
1.192 +{
1.193 + maple_device_t device;
1.194 + KeyBindingField *field[MAX_KEY_BINDINGS][2];
1.195 +}
1.196 +- (id)initWithFrame: (NSRect)frameRect;
1.197 +- (void)setDevice: (maple_device_t)device;
1.198 +@end
1.199 +
1.200 +@implementation ControllerKeyBindingView
1.201 +- (id)initWithFrame: (NSRect)frameRect
1.202 +{
1.203 + if( [super initWithFrame: frameRect] == nil ) {
1.204 + return nil;
1.205 + } else {
1.206 + device = NULL;
1.207 + return self;
1.208 + }
1.209 +}
1.210 +- (BOOL)isFlipped
1.211 +{
1.212 + return YES;
1.213 +}
1.214 +- (void)removeSubviews
1.215 +{
1.216 + [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
1.217 +}
1.218 +- (void)controlTextDidChange: (NSNotification *)notify
1.219 +{
1.220 + int binding = [[notify object] tag];
1.221 + NSString *val1 = [field[binding][0] stringValue];
1.222 + NSString *val2 = [field[binding][1] stringValue];
1.223 + char buf[ [val1 length] + [val2 length] + 2 ];
1.224 + const gchar *p = NULL;
1.225 +
1.226 + if( [val1 length] == 0 ) {
1.227 + if( [val2 length] != 0 ) {
1.228 + p = [val2 UTF8String];
1.229 + }
1.230 + } else if( [val2 length] == 0 ) {
1.231 + p = [val1 UTF8String];
1.232 + } else {
1.233 + sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
1.234 + p = buf;
1.235 + }
1.236 + maple_set_device_config_value( device, binding, p );
1.237 + lxdream_save_config();
1.238 +}
1.239 +- (void)setDevice: (maple_device_t)newDevice
1.240 +{
1.241 + device = newDevice;
1.242 + [self removeSubviews];
1.243 + if( device != NULL ) {
1.244 + lxdream_config_entry_t config = maple_get_device_config(device);
1.245 + if( config != NULL ) {
1.246 + int count, i, y, x;
1.247 +
1.248 + for( count=0; config[count].key != NULL; count++ );
1.249 + x = TEXT_GAP;
1.250 + NSSize size = NSMakeSize(85+KEYBINDING_SIZE*2+TEXT_GAP*4, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
1.251 + [self setFrameSize: size];
1.252 + [self scrollRectToVisible: NSMakeRect(0,0,1,1)];
1.253 + y = TEXT_GAP;
1.254 + for( i=0; config[i].key != NULL; i++ ) {
1.255 + NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT);
1.256 + NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame);
1.257 + [label setAlignment: NSRightTextAlignment];
1.258 +
1.259 + frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT);
1.260 + field[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
1.261 + [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.262 + [field[i][0] setTag: i];
1.263 + [field[i][0] setDelegate: self];
1.264 + [self addSubview: field[i][0]];
1.265 +
1.266 + frame = NSMakeRect( x + 85 + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT);
1.267 + field[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
1.268 + [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.269 + [field[i][1] setTag: i];
1.270 + [field[i][1] setDelegate: self];
1.271 + [self addSubview: field[i][1]];
1.272 +
1.273 + if( config[i].value != NULL ) {
1.274 + gchar **parts = g_strsplit(config[i].value,",",3);
1.275 + if( parts[0] != NULL ) {
1.276 + [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
1.277 + if( parts[1] != NULL ) {
1.278 + [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
1.279 + }
1.280 + }
1.281 + g_strfreev(parts);
1.282 + }
1.283 +
1.284 + y += (TEXT_HEIGHT + TEXT_GAP);
1.285 + }
1.286 + } else {
1.287 + [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.288 + }
1.289 + } else {
1.290 + [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.291 + }
1.292 +}
1.293 +@end
1.294 +
1.295 +/*************************** Top-level controller pane ***********************/
1.296 +
1.297 +@interface LxdreamPrefsControllerPane: LxdreamPrefsPane
1.298 +{
1.299 + struct maple_device *save_controller[4];
1.300 + NSButton *radio[4];
1.301 + ControllerKeyBindingView *key_bindings;
1.302 +}
1.303 ++ (LxdreamPrefsControllerPane *)new;
1.304 +@end
1.305 +
1.306 +@implementation LxdreamPrefsControllerPane
1.307 ++ (LxdreamPrefsControllerPane *)new
1.308 +{
1.309 + return [[LxdreamPrefsControllerPane alloc] initWithFrame: NSMakeRect(0,0,600,400)];
1.310 +}
1.311 +- (id)initWithFrame: (NSRect)frameRect
1.312 +{
1.313 + if( [super initWithFrame: frameRect title: NS_("Controllers")] == nil ) {
1.314 + return nil;
1.315 + } else {
1.316 + const struct maple_device_class **devices = maple_get_device_classes();
1.317 + char buf[16];
1.318 + int i,j;
1.319 + int y = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
1.320 +
1.321 + NSBox *rule = [[NSBox alloc] initWithFrame:
1.322 + NSMakeRect(210+(TEXT_GAP*3), 1, 1, [self contentHeight] + TEXT_GAP - 2)];
1.323 + [rule setAutoresizingMask: (NSViewMaxXMargin|NSViewHeightSizable)];
1.324 + [rule setBoxType: NSBoxSeparator];
1.325 + [self addSubview: rule];
1.326 +
1.327 + NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
1.328 + frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
1.329 + NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
1.330 + key_bindings = [[ControllerKeyBindingView alloc] initWithFrame: bindingFrame ];
1.331 + [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
1.332 + [scrollView setDocumentView: key_bindings];
1.333 + [scrollView setDrawsBackground: NO];
1.334 + [scrollView setHasVerticalScroller: YES];
1.335 + [scrollView setAutohidesScrollers: YES];
1.336 +
1.337 + [self addSubview: scrollView];
1.338 + [key_bindings setDevice: maple_get_device(0,0)];
1.339 +
1.340 + for( i=0; i<MAX_DEVICES; i++ ) {
1.341 + int x = TEXT_GAP;
1.342 + save_controller[i] = NULL;
1.343 + maple_device_t device = maple_get_device(i,0);
1.344 +
1.345 + snprintf( buf, sizeof(buf), _("Slot %d."), i );
1.346 + radio[i] = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )];
1.347 + [radio[i] setTitle: [NSString stringWithUTF8String: buf]];
1.348 + [radio[i] setTag: i];
1.349 + [radio[i] setButtonType: NSRadioButton];
1.350 + [radio[i] setAlignment: NSRightTextAlignment];
1.351 + [radio[i] setTarget: self];
1.352 + [radio[i] setAction: @selector(radioChanged:)];
1.353 + [radio[i] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.354 + [self addSubview: radio[i]];
1.355 + x += 60 + TEXT_GAP;
1.356 +
1.357 + NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: NSMakeRect(x,y,150,TEXT_HEIGHT)
1.358 + pullsDown: NO];
1.359 + [popup addItemWithTitle: NS_("<empty>")];
1.360 + [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.361 + [[popup itemAtIndex: 0] setTag: 0];
1.362 + for( j=0; devices[j] != NULL; j++ ) {
1.363 + [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]];
1.364 + if( device != NULL && device->device_class == devices[j] ) {
1.365 + [popup selectItemAtIndex: (j+1)];
1.366 + }
1.367 + [[popup itemAtIndex: (j+1)] setTag: (j+1)];
1.368 + }
1.369 + [popup setTarget: self];
1.370 + [popup setAction: @selector(deviceChanged:)];
1.371 + [popup setTag: i];
1.372 + [self addSubview: popup];
1.373 + y -= (TEXT_HEIGHT+TEXT_GAP);
1.374 + }
1.375 +
1.376 + [radio[0] setState: NSOnState];
1.377 + return self;
1.378 + }
1.379 +}
1.380 +- (void)radioChanged: (id)sender
1.381 +{
1.382 + int slot = [sender tag];
1.383 + int i;
1.384 + for( i=0; i<MAX_DEVICES; i++ ) {
1.385 + if( i != slot ) {
1.386 + [radio[i] setState: NSOffState];
1.387 + }
1.388 + }
1.389 + [key_bindings setDevice: maple_get_device(slot,0)];
1.390 +}
1.391 +- (void)deviceChanged: (id)sender
1.392 +{
1.393 + int slot = [sender tag];
1.394 + int new_device_idx = [sender indexOfSelectedItem] - 1, i;
1.395 + maple_device_class_t new_device_class = NULL;
1.396 +
1.397 + for( i=0; i<MAX_DEVICES; i++ ) {
1.398 + if( i == slot ) {
1.399 + [radio[i] setState: NSOnState];
1.400 + } else {
1.401 + [radio[i] setState: NSOffState];
1.402 + }
1.403 + }
1.404 +
1.405 + maple_device_t current = maple_get_device(slot,0);
1.406 + maple_device_t new_device = NULL;
1.407 + if( new_device_idx != -1 ) {
1.408 + new_device_class = maple_get_device_classes()[new_device_idx];
1.409 + }
1.410 + if( current == NULL ? new_device_class == NULL : current->device_class == new_device_class ) {
1.411 + // No change
1.412 + [key_bindings setDevice: current];
1.413 + return;
1.414 + }
1.415 + if( current != NULL && current->device_class == &controller_class ) {
1.416 + save_controller[slot] = current->clone(current);
1.417 + }
1.418 + if( new_device_class == NULL ) {
1.419 + maple_detach_device(slot,0);
1.420 + } else {
1.421 + if( new_device_class == &controller_class && save_controller[slot] != NULL ) {
1.422 + new_device = save_controller[slot];
1.423 + save_controller[slot] = NULL;
1.424 + } else {
1.425 + new_device = maple_new_device( new_device_class->name );
1.426 + }
1.427 + maple_attach_device(new_device,slot,0);
1.428 + }
1.429 + [key_bindings setDevice: maple_get_device(slot,0)];
1.430 + lxdream_save_config();
1.431 +}
1.432 +@end
1.433 +
1.434 +NSView *cocoa_gui_create_prefs_controller_pane()
1.435 +{
1.436 + return [LxdreamPrefsControllerPane new];
1.437 +}
.