4 * Construct and manage a configuration pane based on an underlying
7 * Copyright (c) 2009 Nathan Keynes.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
23 #include "maple/maple.h"
25 static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
27 @interface KeyBindingEditor (Private)
28 - (void)updateKeysym: (const gchar *)sym;
31 @implementation KeyBindingEditor
37 [self setFieldEditor: YES];
38 [self setEditable: FALSE];
43 if( lastValue != nil ) {
49 - (void)setPrimed: (BOOL)primed
51 if( primed != isPrimed ) {
54 lastValue = [[NSString stringWithString: [self string]] retain];
55 [self setString: @"<press key>"];
56 input_set_keysym_hook(cocoa_config_keysym_hook, self);
60 input_set_keysym_hook(NULL,NULL);
64 - (BOOL)resignFirstResponder
67 [self setString: lastValue];
70 return [super resignFirstResponder];
72 - (void)fireBindingChanged
74 id delegate = [self delegate];
75 if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
76 [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
80 - (void)updateKeysym: (const gchar *)sym
83 [self setString: [NSString stringWithCString: sym]];
85 [self fireBindingChanged];
88 - (void)updateMousesym: (int)button
90 gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, (button+1) );
91 if( keysym != NULL ) {
92 [self updateKeysym: keysym ];
96 - (void)keyPressed: (int)keycode
98 gchar *keysym = input_keycode_to_keysym(NULL, keycode);
99 if( keysym != NULL ) {
100 [self updateKeysym: keysym];
104 - (void)insertText:(id)string
108 - (void)mouseDown: (NSEvent *)event
111 [self updateMousesym: 0];
113 [self setPrimed: YES];
114 [super mouseDown: event];
117 - (void)rightMouseDown: (NSEvent *)event
120 [self updateMousesym: 1];
123 - (void)otherMouseDown: (NSEvent *)event
126 [self updateMousesym: [event buttonNumber]];
129 - (void)keyDown: (NSEvent *) event
131 NSString *chars = [event characters];
133 if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
134 // Escape char = abort change
135 [self setString: lastValue];
136 [self setPrimed: NO];
138 [self keyPressed: ([event keyCode]+1)];
141 if( chars != NULL && [chars length] == 1 ) {
142 int ch = [chars characterAtIndex: 0];
145 [self setString: @""];
146 [self fireBindingChanged];
149 [self setPrimed: YES];
152 [super keyDown: event];
156 [super keyDown: event];
160 - (void)flagsChanged: (NSEvent *) event
163 [self keyPressed: ([event keyCode]+1)];
165 [super flagsChanged: event];
169 static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
171 KeyBindingEditor *editor = (KeyBindingEditor *)data;
172 [editor updateKeysym: keysym];
175 @implementation KeyBindingField
178 /*************************** Configuration sub-view ***********************/
180 #define KEYBINDING_SIZE 110
181 #define DEFAULT_LABEL_WIDTH 150
182 #define RIGHT_MARGIN 40
184 @implementation ConfigurationView
185 - (id)initWithFrame: (NSRect)frameRect
187 return [self initWithFrame: frameRect configGroup: NULL];
189 - (id)initWithFrame: (NSRect)frameRect configGroup: (lxdream_config_group_t)config
191 if( [super initWithFrame: frameRect] == nil ) {
195 labelWidth = DEFAULT_LABEL_WIDTH;
196 [self setConfigGroup: config];
204 - (void)setLabelWidth: (int)width
208 - (void)removeSubviews
210 [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
212 - (void)updateField: (int)binding
214 const gchar *p = NULL;
215 NSString *val1 = [fields[binding][0] stringValue];
216 if( fields[binding][1] == NULL ) {
217 p = [val1 UTF8String];
218 lxdream_set_config_value( group, binding, p );
220 NSString *val2 = [fields[binding][1] stringValue];
221 char buf[ [val1 length] + [val2 length] + 2 ];
223 if( [val1 length] == 0 ) {
224 if( [val2 length] != 0 ) {
225 p = [val2 UTF8String];
227 } else if( [val2 length] == 0 ) {
228 p = [val1 UTF8String];
230 sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
233 lxdream_set_config_value( group, binding, p );
235 lxdream_save_config();
238 - (void)controlTextDidChange: (NSNotification *)notify
240 if( [[notify object] isKindOfClass: [KeyBindingField class]] ) {
241 [self updateField: [[notify object] tag]];
244 - (void)controlTextDidEndEditing: (NSNotification *)notify
246 [self updateField: [[notify object] tag]];
249 - (void)openFileDialog: (id)sender
251 int tag = [sender tag];
252 NSString *text = [fields[tag][0] stringValue];
253 NSOpenPanel *panel = [NSOpenPanel openPanel];
254 int result = [panel runModalForDirectory: nil file: nil types: nil];
255 if( result == NSOKButton && [[panel filenames] count] > 0 ) {
256 NSString *filename = [[panel filenames] objectAtIndex: 0];
257 gchar *str = get_escaped_path( [filename UTF8String] );
258 [fields[tag][0] setStringValue: [NSString stringWithUTF8String: str]];
259 lxdream_set_global_config_value(tag,str);
260 lxdream_save_config();
263 - (void)openDirDialog: (id)sender
265 int tag = [sender tag];
266 NSString *text = [fields[tag][0] stringValue];
267 NSOpenPanel *panel = [NSOpenPanel openPanel];
268 [panel setCanChooseDirectories: YES];
269 [panel setCanCreateDirectories: YES];
270 int result = [panel runModalForDirectory: nil file: nil types: nil];
271 if( result == NSOKButton && [[panel filenames] count] > 0 ) {
272 NSString *filename = [[panel filenames] objectAtIndex: 0];
273 gchar *str = get_escaped_path( [filename UTF8String] );
274 [fields[tag][0] setStringValue: [NSString stringWithUTF8String: str]];
275 lxdream_set_global_config_value(tag,str);
276 lxdream_save_config();
280 - (void)setConfigGroup: (lxdream_config_group_t) config
282 if( group == config ) {
285 int width = [self frame].size.width;
289 [self removeSubviews];
290 if( config != NULL && config->params[0].key != NULL ) {
293 for( count=0; config->params[count].label != NULL; count++ );
294 int minWidth = labelWidth+KEYBINDING_SIZE*2+TEXT_GAP*4;
295 if( minWidth > width ) {
298 NSSize size = NSMakeSize( width, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
299 [self setFrameSize: size];
300 [self scrollRectToVisible: NSMakeRect(0,0,1,1)];
304 for( i=0; config->params[i].label != NULL; i++ ) {
306 NSRect frame = NSMakeRect(x, y + 2, labelWidth, LABEL_HEIGHT);
307 NSTextField *label = cocoa_gui_add_label(self, NS_(config->params[i].label), frame);
308 [label setAlignment: NSRightTextAlignment];
310 switch(config->params[i].type) {
311 case CONFIG_TYPE_KEY:
312 frame = NSMakeRect( x + labelWidth + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT);
313 fields[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
314 [fields[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
315 [fields[i][0] setTag: i];
316 [fields[i][0] setDelegate: self];
317 [self addSubview: fields[i][0]];
319 frame = NSMakeRect( x + labelWidth + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT);
320 fields[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
321 [fields[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
322 [fields[i][1] setTag: i];
323 [fields[i][1] setDelegate: self];
324 [self addSubview: fields[i][1]];
326 if( config->params[i].value != NULL ) {
327 gchar **parts = g_strsplit(config->params[i].value,",",3);
328 if( parts[0] != NULL ) {
329 [fields[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
330 if( parts[1] != NULL ) {
331 [fields[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
337 case CONFIG_TYPE_FILE:
338 case CONFIG_TYPE_PATH:
339 fieldWidth = width - labelWidth - x - TEXT_HEIGHT - RIGHT_MARGIN - (TEXT_GAP*2);
340 frame = NSMakeRect( x + labelWidth + TEXT_GAP, y, fieldWidth, TEXT_HEIGHT );
341 NSTextField *field = [[NSTextField alloc] initWithFrame: frame];
343 [field setStringValue: [NSString stringWithCString: config->params[i].value]];
344 [field setDelegate: self];
345 [field setAutoresizingMask: (NSViewMinYMargin|NSViewWidthSizable)];
347 frame = NSMakeRect( x+ labelWidth + fieldWidth + (TEXT_GAP*2), y, TEXT_HEIGHT, TEXT_HEIGHT );
348 NSButton *button = [[NSButton alloc] initWithFrame: frame];
350 [button setTitle: @""];
351 [button setButtonType: NSMomentaryPushInButton];
352 [button setBezelStyle: NSRoundedDisclosureBezelStyle];
353 [button setAutoresizingMask: (NSViewMinYMargin|NSViewMinXMargin)];
354 [button setTarget: self];
355 if( config->params[i].type == CONFIG_TYPE_FILE ) {
356 [button setAction: @selector(openFileDialog:)];
358 [button setAction: @selector(openDirDialog:)];
361 [self addSubview: label];
362 [self addSubview: field];
363 [self addSubview: button];
364 fields[i][0] = field;
367 y += (TEXT_HEIGHT + TEXT_GAP);
370 [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
374 - (void)setDevice: (maple_device_t)newDevice
376 if( newDevice != NULL && !MAPLE_IS_VMU(newDevice) ) {
377 [self setConfigGroup: maple_get_device_config(newDevice)];
379 [self setConfigGroup: NULL];
.