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 1072:d82e04e6d497
prev1069:7e2b65496762
next1297:7e98a164b2d9
author nkeynes
date Tue Jul 21 20:33:21 2009 +1000 (12 years ago)
permissions -rw-r--r--
last change Heavy configuration management refactor
- Configuration groups now take both an on_change event handler and a
default keybinding handler, making most keybinding tasks quite simple
- GUI configuration all merged into a unified model, drastically reducing
the amount of GUI config code.

Bonuses
- OSX now has a hotkey preference pane
- GTK keybinding editor is much more usable
file annotate diff log raw
1.1 --- a/src/cocoaui/cocoa_ctrl.m Thu Jul 09 08:50:41 2009 +1000
1.2 +++ b/src/cocoaui/cocoa_ctrl.m Tue Jul 21 20:33:21 2009 +1000
1.3 @@ -31,291 +31,10 @@
1.4 #define LOAD_VMU_TAG -1
1.5 #define CREATE_VMU_TAG -2
1.6
1.7 -#define KEYBINDING_SIZE 110
1.8 +#define LABEL_WIDTH 85
1.9
1.10 -static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
1.11 +
1.12 static gboolean cocoa_config_vmulist_hook(vmulist_change_type_t type, int idx, void *data);
1.13 -
1.14 -@interface KeyBindingEditor (Private)
1.15 -- (void)updateKeysym: (const gchar *)sym;
1.16 -@end
1.17 -
1.18 -@implementation KeyBindingEditor
1.19 -- (id)init
1.20 -{
1.21 - self = [super init];
1.22 - isPrimed = NO;
1.23 - lastValue = nil;
1.24 - [self setFieldEditor: YES];
1.25 - [self setEditable: FALSE];
1.26 - return self;
1.27 -}
1.28 -- (void)dealloc
1.29 -{
1.30 - if( lastValue != nil ) {
1.31 - [lastValue release];
1.32 - lastValue = nil;
1.33 - }
1.34 - [super dealloc];
1.35 -}
1.36 -- (void)setPrimed: (BOOL)primed
1.37 -{
1.38 - if( primed != isPrimed ) {
1.39 - isPrimed = primed;
1.40 - if( primed ) {
1.41 - lastValue = [[NSString stringWithString: [self string]] retain];
1.42 - [self setString: @"<press key>"];
1.43 - input_set_keysym_hook(cocoa_config_keysym_hook, self);
1.44 - } else {
1.45 - [lastValue release];
1.46 - lastValue = nil;
1.47 - input_set_keysym_hook(NULL,NULL);
1.48 - }
1.49 - }
1.50 -}
1.51 -- (BOOL)resignFirstResponder
1.52 -{
1.53 - if( isPrimed ) {
1.54 - [self setString: lastValue];
1.55 - [self setPrimed: NO];
1.56 - }
1.57 - return [super resignFirstResponder];
1.58 -}
1.59 -- (void)fireBindingChanged
1.60 -{
1.61 - id delegate = [self delegate];
1.62 - if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
1.63 - [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
1.64 - }
1.65 -}
1.66 -
1.67 -- (void)updateKeysym: (const gchar *)sym
1.68 -{
1.69 - if( sym != NULL ) {
1.70 - [self setString: [NSString stringWithCString: sym]];
1.71 - [self setPrimed: NO];
1.72 - [self fireBindingChanged];
1.73 - }
1.74 -}
1.75 -- (void)updateMousesym: (int)button
1.76 -{
1.77 - gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, (button+1) );
1.78 - if( keysym != NULL ) {
1.79 - [self updateKeysym: keysym ];
1.80 - g_free(keysym);
1.81 - }
1.82 -}
1.83 -- (void)keyPressed: (int)keycode
1.84 -{
1.85 - gchar *keysym = input_keycode_to_keysym(NULL, keycode);
1.86 - if( keysym != NULL ) {
1.87 - [self updateKeysym: keysym];
1.88 - g_free(keysym);
1.89 - }
1.90 -}
1.91 -- (void)insertText:(id)string
1.92 -{
1.93 - // Do nothing
1.94 -}
1.95 -- (void)mouseDown: (NSEvent *)event
1.96 -{
1.97 - if( isPrimed ) {
1.98 - [self updateMousesym: 0];
1.99 - } else {
1.100 - [self setPrimed: YES];
1.101 - [super mouseDown: event];
1.102 - }
1.103 -}
1.104 -- (void)rightMouseDown: (NSEvent *)event
1.105 -{
1.106 - if( isPrimed ) {
1.107 - [self updateMousesym: 1];
1.108 - }
1.109 -}
1.110 -- (void)otherMouseDown: (NSEvent *)event
1.111 -{
1.112 - if( isPrimed ) {
1.113 - [self updateMousesym: [event buttonNumber]];
1.114 - }
1.115 -}
1.116 -- (void)keyDown: (NSEvent *) event
1.117 -{
1.118 - NSString *chars = [event characters];
1.119 - if( isPrimed ) {
1.120 - if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
1.121 - // Escape char = abort change
1.122 - [self setString: lastValue];
1.123 - [self setPrimed: NO];
1.124 - } else {
1.125 - [self keyPressed: ([event keyCode]+1)];
1.126 - }
1.127 - } else {
1.128 - if( chars != NULL && [chars length] == 1 ) {
1.129 - int ch = [chars characterAtIndex: 0];
1.130 - switch( ch ) {
1.131 - case 0x7F:
1.132 - [self setString: @""];
1.133 - [self fireBindingChanged];
1.134 - break;
1.135 - case '\r':
1.136 - [self setPrimed: YES];
1.137 - break;
1.138 - default:
1.139 - [super keyDown: event];
1.140 - break;
1.141 - }
1.142 - } else {
1.143 - [super keyDown: event];
1.144 - }
1.145 - }
1.146 -}
1.147 -- (void)flagsChanged: (NSEvent *) event
1.148 -{
1.149 - if( isPrimed ) {
1.150 - [self keyPressed: ([event keyCode]+1)];
1.151 - }
1.152 - [super flagsChanged: event];
1.153 -}
1.154 -@end
1.155 -
1.156 -static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
1.157 -{
1.158 - KeyBindingEditor *editor = (KeyBindingEditor *)data;
1.159 - [editor updateKeysym: keysym];
1.160 -}
1.161 -
1.162 -
1.163 -@implementation KeyBindingField
1.164 -@end
1.165 -
1.166 -/*************************** Key-binding sub-view ***********************/
1.167 -
1.168 -#define MAX_KEY_BINDINGS 32
1.169 -
1.170 -@interface ControllerKeyBindingView : NSView
1.171 -{
1.172 - maple_device_t device;
1.173 - NSTextField *field[MAX_KEY_BINDINGS][2];
1.174 -}
1.175 -- (id)initWithFrame: (NSRect)frameRect;
1.176 -- (void)setDevice: (maple_device_t)device;
1.177 -@end
1.178 -
1.179 -@implementation ControllerKeyBindingView
1.180 -- (id)initWithFrame: (NSRect)frameRect
1.181 -{
1.182 - if( [super initWithFrame: frameRect] == nil ) {
1.183 - return nil;
1.184 - } else {
1.185 - device = NULL;
1.186 - return self;
1.187 - }
1.188 -}
1.189 -- (BOOL)isFlipped
1.190 -{
1.191 - return YES;
1.192 -}
1.193 -- (void)removeSubviews
1.194 -{
1.195 - [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
1.196 -}
1.197 -- (void)controlTextDidChange: (NSNotification *)notify
1.198 -{
1.199 - const gchar *p = NULL;
1.200 - int binding = [[notify object] tag];
1.201 - NSString *val1 = [field[binding][0] stringValue];
1.202 - if( field[binding][1] == NULL ) {
1.203 - p = [val1 UTF8String];
1.204 - } else {
1.205 - NSString *val2 = [field[binding][1] stringValue];
1.206 - char buf[ [val1 length] + [val2 length] + 2 ];
1.207 -
1.208 - if( [val1 length] == 0 ) {
1.209 - if( [val2 length] != 0 ) {
1.210 - p = [val2 UTF8String];
1.211 - }
1.212 - } else if( [val2 length] == 0 ) {
1.213 - p = [val1 UTF8String];
1.214 - } else {
1.215 - sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
1.216 - p = buf;
1.217 - }
1.218 - }
1.219 - maple_set_device_config_value( device, binding, p );
1.220 - lxdream_save_config();
1.221 -}
1.222 -- (void)setDevice: (maple_device_t)newDevice
1.223 -{
1.224 - device = newDevice;
1.225 - [self removeSubviews];
1.226 - if( device != NULL && !MAPLE_IS_VMU(device) ) {
1.227 - lxdream_config_entry_t config = maple_get_device_config(device);
1.228 - if( config != NULL ) {
1.229 - int count, i, y, x;
1.230 -
1.231 - for( count=0; config[count].key != NULL; count++ );
1.232 - x = TEXT_GAP;
1.233 - NSSize size = NSMakeSize(85+KEYBINDING_SIZE*2+TEXT_GAP*4, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
1.234 - [self setFrameSize: size];
1.235 - [self scrollRectToVisible: NSMakeRect(0,0,1,1)];
1.236 - y = TEXT_GAP;
1.237 - for( i=0; config[i].key != NULL; i++ ) {
1.238 - /* Add label */
1.239 - NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT);
1.240 - NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame);
1.241 - [label setAlignment: NSRightTextAlignment];
1.242 -
1.243 - switch(config[i].type) {
1.244 - case CONFIG_TYPE_KEY:
1.245 - frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT);
1.246 - field[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
1.247 - [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.248 - [field[i][0] setTag: i];
1.249 - [field[i][0] setDelegate: self];
1.250 - [self addSubview: field[i][0]];
1.251 -
1.252 - frame = NSMakeRect( x + 85 + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT);
1.253 - field[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
1.254 - [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.255 - [field[i][1] setTag: i];
1.256 - [field[i][1] setDelegate: self];
1.257 - [self addSubview: field[i][1]];
1.258 -
1.259 - if( config[i].value != NULL ) {
1.260 - gchar **parts = g_strsplit(config[i].value,",",3);
1.261 - if( parts[0] != NULL ) {
1.262 - [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
1.263 - if( parts[1] != NULL ) {
1.264 - [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
1.265 - }
1.266 - }
1.267 - g_strfreev(parts);
1.268 - }
1.269 - break;
1.270 - case CONFIG_TYPE_FILE:
1.271 - case CONFIG_TYPE_PATH:
1.272 - frame = NSMakeRect( x + 85 + TEXT_GAP, y, KEYBINDING_SIZE*2+TEXT_GAP, TEXT_HEIGHT);
1.273 - field[i][0] = [[NSTextField alloc] initWithFrame: frame];
1.274 - [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
1.275 - [field[i][0] setTag: i];
1.276 - [field[i][0] setDelegate: self];
1.277 - [self addSubview: field[i][0]];
1.278 - if( config[i].value != NULL ) {
1.279 - [field[i][0] setStringValue: [NSString stringWithCString: config[i].value]];
1.280 - }
1.281 - field[i][1] = NULL;
1.282 - }
1.283 - y += (TEXT_HEIGHT + TEXT_GAP);
1.284 - }
1.285 - } else {
1.286 - [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.287 - }
1.288 - } else {
1.289 - [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
1.290 - }
1.291 -}
1.292 -@end
1.293 -
1.294 /*************************** Top-level controller pane ***********************/
1.295 static NSButton *addRadioButton( int port, int sub, int x, int y, id parent )
1.296 {
1.297 @@ -385,10 +104,14 @@
1.298
1.299 if( !primary ) {
1.300 BOOL vmu_selected = NO;
1.301 - const char *vmu_name;
1.302 + const char *vmu_name = NULL;
1.303 if( device != NULL && MAPLE_IS_VMU(device) ) {
1.304 - vmu_selected = YES;
1.305 vmu_name = MAPLE_VMU_NAME(device);
1.306 + if( vmu_name == NULL ) {
1.307 + device = NULL;
1.308 + } else {
1.309 + vmu_selected = YES;
1.310 + }
1.311 }
1.312 if( [popup numberOfItems] > 0 ) {
1.313 [[popup menu] addItem: [NSMenuItem separatorItem]];
1.314 @@ -474,7 +197,7 @@
1.315 struct maple_device *save_controller[MAPLE_MAX_DEVICES];
1.316 NSButton *radio[MAPLE_MAX_DEVICES];
1.317 NSPopUpButton *popup[MAPLE_MAX_DEVICES];
1.318 - ControllerKeyBindingView *key_bindings;
1.319 + ConfigurationView *key_bindings;
1.320 }
1.321 + (LxdreamPrefsControllerPane *)new;
1.322 - (void)vmulistChanged: (id)sender;
1.323 @@ -511,7 +234,8 @@
1.324 NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
1.325 frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
1.326 NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
1.327 - key_bindings = [[ControllerKeyBindingView alloc] initWithFrame: bindingFrame ];
1.328 + key_bindings = [[ConfigurationView alloc] initWithFrame: bindingFrame ];
1.329 + [key_bindings setLabelWidth: LABEL_WIDTH];
1.330 [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
1.331 [scrollView setDocumentView: key_bindings];
1.332 [scrollView setDrawsBackground: NO];
.