nkeynes@1072: /** nkeynes@1072: * $Id$ nkeynes@1072: * nkeynes@1072: * Construct and manage a configuration pane based on an underlying nkeynes@1072: * configuration group. nkeynes@1072: * nkeynes@1072: * Copyright (c) 2009 Nathan Keynes. nkeynes@1072: * nkeynes@1072: * This program is free software; you can redistribute it and/or modify nkeynes@1072: * it under the terms of the GNU General Public License as published by nkeynes@1072: * the Free Software Foundation; either version 2 of the License, or nkeynes@1072: * (at your option) any later version. nkeynes@1072: * nkeynes@1072: * This program is distributed in the hope that it will be useful, nkeynes@1072: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@1072: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@1072: * GNU General Public License for more details. nkeynes@1072: */ nkeynes@1072: nkeynes@1072: #include "cocoaui.h" nkeynes@1072: #include "display.h" nkeynes@1072: #include "lxpaths.h" nkeynes@1072: #include "maple/maple.h" nkeynes@1072: nkeynes@1072: static void cocoa_config_keysym_hook(void *data, const gchar *keysym); nkeynes@1072: nkeynes@1072: @interface KeyBindingEditor (Private) nkeynes@1072: - (void)updateKeysym: (const gchar *)sym; nkeynes@1072: @end nkeynes@1072: nkeynes@1072: @implementation KeyBindingEditor nkeynes@1072: - (id)init nkeynes@1072: { nkeynes@1072: self = [super init]; nkeynes@1072: isPrimed = NO; nkeynes@1072: lastValue = nil; nkeynes@1072: [self setFieldEditor: YES]; nkeynes@1072: [self setEditable: FALSE]; nkeynes@1072: return self; nkeynes@1072: } nkeynes@1072: - (void)dealloc nkeynes@1072: { nkeynes@1072: if( lastValue != nil ) { nkeynes@1072: [lastValue release]; nkeynes@1072: lastValue = nil; nkeynes@1072: } nkeynes@1072: [super dealloc]; nkeynes@1072: } nkeynes@1072: - (void)setPrimed: (BOOL)primed nkeynes@1072: { nkeynes@1072: if( primed != isPrimed ) { nkeynes@1072: isPrimed = primed; nkeynes@1072: if( primed ) { nkeynes@1072: lastValue = [[NSString stringWithString: [self string]] retain]; nkeynes@1072: [self setString: @""]; nkeynes@1072: input_set_keysym_hook(cocoa_config_keysym_hook, self); nkeynes@1072: } else { nkeynes@1072: [lastValue release]; nkeynes@1072: lastValue = nil; nkeynes@1072: input_set_keysym_hook(NULL,NULL); nkeynes@1072: } nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (BOOL)resignFirstResponder nkeynes@1072: { nkeynes@1072: if( isPrimed ) { nkeynes@1072: [self setString: lastValue]; nkeynes@1072: [self setPrimed: NO]; nkeynes@1072: } nkeynes@1072: return [super resignFirstResponder]; nkeynes@1072: } nkeynes@1072: - (void)fireBindingChanged nkeynes@1072: { nkeynes@1072: id delegate = [self delegate]; nkeynes@1072: if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) { nkeynes@1072: [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: nkeynes@1072: - (void)updateKeysym: (const gchar *)sym nkeynes@1072: { nkeynes@1072: if( sym != NULL ) { nkeynes@1072: [self setString: [NSString stringWithCString: sym]]; nkeynes@1072: [self setPrimed: NO]; nkeynes@1072: [self fireBindingChanged]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)updateMousesym: (int)button nkeynes@1072: { nkeynes@1072: gchar *keysym = input_keycode_to_keysym( &system_mouse_driver, (button+1) ); nkeynes@1072: if( keysym != NULL ) { nkeynes@1072: [self updateKeysym: keysym ]; nkeynes@1072: g_free(keysym); nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)keyPressed: (int)keycode nkeynes@1072: { nkeynes@1072: gchar *keysym = input_keycode_to_keysym(NULL, keycode); nkeynes@1072: if( keysym != NULL ) { nkeynes@1072: [self updateKeysym: keysym]; nkeynes@1072: g_free(keysym); nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)insertText:(id)string nkeynes@1072: { nkeynes@1072: // Do nothing nkeynes@1072: } nkeynes@1072: - (void)mouseDown: (NSEvent *)event nkeynes@1072: { nkeynes@1072: if( isPrimed ) { nkeynes@1072: [self updateMousesym: 0]; nkeynes@1072: } else { nkeynes@1072: [self setPrimed: YES]; nkeynes@1072: [super mouseDown: event]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)rightMouseDown: (NSEvent *)event nkeynes@1072: { nkeynes@1072: if( isPrimed ) { nkeynes@1072: [self updateMousesym: 1]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)otherMouseDown: (NSEvent *)event nkeynes@1072: { nkeynes@1072: if( isPrimed ) { nkeynes@1072: [self updateMousesym: [event buttonNumber]]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)keyDown: (NSEvent *) event nkeynes@1072: { nkeynes@1072: NSString *chars = [event characters]; nkeynes@1072: if( isPrimed ) { nkeynes@1072: if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) { nkeynes@1072: // Escape char = abort change nkeynes@1072: [self setString: lastValue]; nkeynes@1072: [self setPrimed: NO]; nkeynes@1072: } else { nkeynes@1072: [self keyPressed: ([event keyCode]+1)]; nkeynes@1072: } nkeynes@1072: } else { nkeynes@1072: if( chars != NULL && [chars length] == 1 ) { nkeynes@1072: int ch = [chars characterAtIndex: 0]; nkeynes@1072: switch( ch ) { nkeynes@1072: case 0x7F: nkeynes@1072: [self setString: @""]; nkeynes@1072: [self fireBindingChanged]; nkeynes@1072: break; nkeynes@1072: case '\r': nkeynes@1072: [self setPrimed: YES]; nkeynes@1072: break; nkeynes@1072: default: nkeynes@1072: [super keyDown: event]; nkeynes@1072: break; nkeynes@1072: } nkeynes@1072: } else { nkeynes@1072: [super keyDown: event]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)flagsChanged: (NSEvent *) event nkeynes@1072: { nkeynes@1072: if( isPrimed ) { nkeynes@1072: [self keyPressed: ([event keyCode]+1)]; nkeynes@1072: } nkeynes@1072: [super flagsChanged: event]; nkeynes@1072: } nkeynes@1072: @end nkeynes@1072: nkeynes@1072: static void cocoa_config_keysym_hook(void *data, const gchar *keysym) nkeynes@1072: { nkeynes@1072: KeyBindingEditor *editor = (KeyBindingEditor *)data; nkeynes@1072: [editor updateKeysym: keysym]; nkeynes@1072: } nkeynes@1072: nkeynes@1072: @implementation KeyBindingField nkeynes@1072: @end nkeynes@1072: nkeynes@1072: /*************************** Configuration sub-view ***********************/ nkeynes@1072: nkeynes@1072: #define KEYBINDING_SIZE 110 nkeynes@1072: #define DEFAULT_LABEL_WIDTH 150 nkeynes@1072: #define RIGHT_MARGIN 40 nkeynes@1072: nkeynes@1072: @implementation ConfigurationView nkeynes@1072: - (id)initWithFrame: (NSRect)frameRect nkeynes@1072: { nkeynes@1072: return [self initWithFrame: frameRect configGroup: NULL]; nkeynes@1072: } nkeynes@1072: - (id)initWithFrame: (NSRect)frameRect configGroup: (lxdream_config_group_t)config nkeynes@1072: { nkeynes@1072: if( [super initWithFrame: frameRect] == nil ) { nkeynes@1072: return nil; nkeynes@1072: } else { nkeynes@1072: group = NULL; nkeynes@1072: labelWidth = DEFAULT_LABEL_WIDTH; nkeynes@1072: [self setConfigGroup: config]; nkeynes@1072: return self; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (BOOL)isFlipped nkeynes@1072: { nkeynes@1072: return YES; nkeynes@1072: } nkeynes@1072: - (void)setLabelWidth: (int)width nkeynes@1072: { nkeynes@1072: labelWidth = width; nkeynes@1072: } nkeynes@1072: - (void)removeSubviews nkeynes@1072: { nkeynes@1072: [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)]; nkeynes@1072: } nkeynes@1072: - (void)updateField: (int)binding nkeynes@1072: { nkeynes@1072: const gchar *p = NULL; nkeynes@1072: NSString *val1 = [fields[binding][0] stringValue]; nkeynes@1072: if( fields[binding][1] == NULL ) { nkeynes@1072: p = [val1 UTF8String]; nkeynes@1072: lxdream_set_config_value( group, binding, p ); nkeynes@1072: } else { nkeynes@1072: NSString *val2 = [fields[binding][1] stringValue]; nkeynes@1072: char buf[ [val1 length] + [val2 length] + 2 ]; nkeynes@1072: nkeynes@1072: if( [val1 length] == 0 ) { nkeynes@1072: if( [val2 length] != 0 ) { nkeynes@1072: p = [val2 UTF8String]; nkeynes@1072: } nkeynes@1072: } else if( [val2 length] == 0 ) { nkeynes@1072: p = [val1 UTF8String]; nkeynes@1072: } else { nkeynes@1072: sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] ); nkeynes@1072: p = buf; nkeynes@1072: } nkeynes@1072: lxdream_set_config_value( group, binding, p ); nkeynes@1072: } nkeynes@1072: lxdream_save_config(); nkeynes@1072: } nkeynes@1072: nkeynes@1072: - (void)controlTextDidChange: (NSNotification *)notify nkeynes@1072: { nkeynes@1072: if( [[notify object] isKindOfClass: [KeyBindingField class]] ) { nkeynes@1072: [self updateField: [[notify object] tag]]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)controlTextDidEndEditing: (NSNotification *)notify nkeynes@1072: { nkeynes@1072: [self updateField: [[notify object] tag]]; nkeynes@1072: } nkeynes@1072: nkeynes@1072: - (void)openFileDialog: (id)sender nkeynes@1072: { nkeynes@1072: int tag = [sender tag]; nkeynes@1072: NSString *text = [fields[tag][0] stringValue]; nkeynes@1072: NSOpenPanel *panel = [NSOpenPanel openPanel]; nkeynes@1072: int result = [panel runModalForDirectory: nil file: nil types: nil]; nkeynes@1072: if( result == NSOKButton && [[panel filenames] count] > 0 ) { nkeynes@1072: NSString *filename = [[panel filenames] objectAtIndex: 0]; nkeynes@1072: gchar *str = get_escaped_path( [filename UTF8String] ); nkeynes@1072: [fields[tag][0] setStringValue: [NSString stringWithUTF8String: str]]; nkeynes@1072: lxdream_set_global_config_value(tag,str); nkeynes@1072: lxdream_save_config(); nkeynes@1072: } nkeynes@1072: } nkeynes@1072: - (void)openDirDialog: (id)sender nkeynes@1072: { nkeynes@1072: int tag = [sender tag]; nkeynes@1072: NSString *text = [fields[tag][0] stringValue]; nkeynes@1072: NSOpenPanel *panel = [NSOpenPanel openPanel]; nkeynes@1072: [panel setCanChooseDirectories: YES]; nkeynes@1072: [panel setCanCreateDirectories: YES]; nkeynes@1072: int result = [panel runModalForDirectory: nil file: nil types: nil]; nkeynes@1072: if( result == NSOKButton && [[panel filenames] count] > 0 ) { nkeynes@1072: NSString *filename = [[panel filenames] objectAtIndex: 0]; nkeynes@1072: gchar *str = get_escaped_path( [filename UTF8String] ); nkeynes@1072: [fields[tag][0] setStringValue: [NSString stringWithUTF8String: str]]; nkeynes@1072: lxdream_set_global_config_value(tag,str); nkeynes@1072: lxdream_save_config(); nkeynes@1072: } nkeynes@1072: } nkeynes@1072: nkeynes@1072: - (void)setConfigGroup: (lxdream_config_group_t) config nkeynes@1072: { nkeynes@1072: if( group == config ) { nkeynes@1072: return; nkeynes@1072: } nkeynes@1072: int width = [self frame].size.width; nkeynes@1072: int fieldWidth; nkeynes@1072: nkeynes@1072: group = config; nkeynes@1072: [self removeSubviews]; nkeynes@1072: if( config != NULL && config->params[0].key != NULL ) { nkeynes@1072: int count, i, y, x; nkeynes@1072: nkeynes@1072: for( count=0; config->params[count].label != NULL; count++ ); nkeynes@1072: int minWidth = labelWidth+KEYBINDING_SIZE*2+TEXT_GAP*4; nkeynes@1072: if( minWidth > width ) { nkeynes@1072: width = minWidth; nkeynes@1072: } nkeynes@1072: NSSize size = NSMakeSize( width, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP); nkeynes@1072: [self setFrameSize: size]; nkeynes@1072: [self scrollRectToVisible: NSMakeRect(0,0,1,1)]; nkeynes@1072: nkeynes@1072: x = TEXT_GAP; nkeynes@1072: y = TEXT_GAP; nkeynes@1072: for( i=0; config->params[i].label != NULL; i++ ) { nkeynes@1072: /* Add label */ nkeynes@1072: NSRect frame = NSMakeRect(x, y + 2, labelWidth, LABEL_HEIGHT); nkeynes@1072: NSTextField *label = cocoa_gui_add_label(self, NS_(config->params[i].label), frame); nkeynes@1072: [label setAlignment: NSRightTextAlignment]; nkeynes@1072: nkeynes@1072: switch(config->params[i].type) { nkeynes@1072: case CONFIG_TYPE_KEY: nkeynes@1072: frame = NSMakeRect( x + labelWidth + TEXT_GAP, y, KEYBINDING_SIZE, TEXT_HEIGHT); nkeynes@1072: fields[i][0] = [[KeyBindingField alloc] initWithFrame: frame]; nkeynes@1072: [fields[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; nkeynes@1072: [fields[i][0] setTag: i]; nkeynes@1072: [fields[i][0] setDelegate: self]; nkeynes@1072: [self addSubview: fields[i][0]]; nkeynes@1072: nkeynes@1072: frame = NSMakeRect( x + labelWidth + KEYBINDING_SIZE + (TEXT_GAP*2), y, KEYBINDING_SIZE, TEXT_HEIGHT); nkeynes@1072: fields[i][1] = [[KeyBindingField alloc] initWithFrame: frame]; nkeynes@1072: [fields[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)]; nkeynes@1072: [fields[i][1] setTag: i]; nkeynes@1072: [fields[i][1] setDelegate: self]; nkeynes@1072: [self addSubview: fields[i][1]]; nkeynes@1072: nkeynes@1072: if( config->params[i].value != NULL ) { nkeynes@1072: gchar **parts = g_strsplit(config->params[i].value,",",3); nkeynes@1072: if( parts[0] != NULL ) { nkeynes@1072: [fields[i][0] setStringValue: [NSString stringWithCString: parts[0]]]; nkeynes@1072: if( parts[1] != NULL ) { nkeynes@1072: [fields[i][1] setStringValue: [NSString stringWithCString: parts[1]]]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: g_strfreev(parts); nkeynes@1072: } nkeynes@1072: break; nkeynes@1072: case CONFIG_TYPE_FILE: nkeynes@1072: case CONFIG_TYPE_PATH: nkeynes@1072: fieldWidth = width - labelWidth - x - TEXT_HEIGHT - RIGHT_MARGIN - (TEXT_GAP*2); nkeynes@1072: frame = NSMakeRect( x + labelWidth + TEXT_GAP, y, fieldWidth, TEXT_HEIGHT ); nkeynes@1072: NSTextField *field = [[NSTextField alloc] initWithFrame: frame]; nkeynes@1072: [field setTag: i]; nkeynes@1072: [field setStringValue: [NSString stringWithCString: config->params[i].value]]; nkeynes@1072: [field setDelegate: self]; nkeynes@1072: [field setAutoresizingMask: (NSViewMinYMargin|NSViewWidthSizable)]; nkeynes@1072: nkeynes@1072: frame = NSMakeRect( x+ labelWidth + fieldWidth + (TEXT_GAP*2), y, TEXT_HEIGHT, TEXT_HEIGHT ); nkeynes@1072: NSButton *button = [[NSButton alloc] initWithFrame: frame]; nkeynes@1072: [button setTag: i]; nkeynes@1072: [button setTitle: @""]; nkeynes@1072: [button setButtonType: NSMomentaryPushInButton]; nkeynes@1072: [button setBezelStyle: NSRoundedDisclosureBezelStyle]; nkeynes@1072: [button setAutoresizingMask: (NSViewMinYMargin|NSViewMinXMargin)]; nkeynes@1072: [button setTarget: self]; nkeynes@1072: if( config->params[i].type == CONFIG_TYPE_FILE ) { nkeynes@1072: [button setAction: @selector(openFileDialog:)]; nkeynes@1072: } else { nkeynes@1072: [button setAction: @selector(openDirDialog:)]; nkeynes@1072: } nkeynes@1072: nkeynes@1072: [self addSubview: label]; nkeynes@1072: [self addSubview: field]; nkeynes@1072: [self addSubview: button]; nkeynes@1072: fields[i][0] = field; nkeynes@1072: fields[i][1] = NULL; nkeynes@1072: } nkeynes@1072: y += (TEXT_HEIGHT + TEXT_GAP); nkeynes@1072: } nkeynes@1072: } else { nkeynes@1072: [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: nkeynes@1072: - (void)setDevice: (maple_device_t)newDevice nkeynes@1072: { nkeynes@1072: if( newDevice != NULL && !MAPLE_IS_VMU(newDevice) ) { nkeynes@1072: [self setConfigGroup: maple_get_device_config(newDevice)]; nkeynes@1072: } else { nkeynes@1072: [self setConfigGroup: NULL]; nkeynes@1072: } nkeynes@1072: } nkeynes@1072: @end nkeynes@1072: