filename | src/cocoaui/cocoa_ctrl.c |
changeset | 787:6717c02ff81f |
prev | 770:429ff505c450 |
next | 849:bbe26d798fc2 |
author | nkeynes |
date | Thu Aug 07 23:32:34 2008 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Unroll first iteration of the bounding loop in ta_commit_polygon - more to remove the compiler warnings than for performance really. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Construct and manage the controller configuration pane
5 *
6 * Copyright (c) 2008 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include "cocoaui.h"
20 #include "config.h"
21 #include "display.h"
22 #include "maple/maple.h"
24 #include <glib/gstrfuncs.h>
26 #define MAX_DEVICES 4
28 static void cocoa_config_keysym_hook(void *data, const gchar *keysym);
30 @interface KeyBindingEditor (Private)
31 - (void)updateKeysym: (const gchar *)sym;
32 @end
34 @implementation KeyBindingEditor
35 - (id)init
36 {
37 self = [super init];
38 isPrimed = NO;
39 lastValue = nil;
40 [self setFieldEditor: YES];
41 [self setEditable: FALSE];
42 return self;
43 }
44 - (void)dealloc
45 {
46 if( lastValue != nil ) {
47 [lastValue release];
48 lastValue = nil;
49 }
50 [super dealloc];
51 }
52 - (void)setPrimed: (BOOL)primed
53 {
54 if( primed != isPrimed ) {
55 isPrimed = primed;
56 if( primed ) {
57 lastValue = [[NSString stringWithString: [self string]] retain];
58 [self setString: @"<press key>"];
59 input_set_keysym_hook(cocoa_config_keysym_hook, self);
60 } else {
61 [lastValue release];
62 lastValue = nil;
63 input_set_keysym_hook(NULL,NULL);
64 }
65 }
66 }
67 - (void)resignFirstResponder
68 {
69 if( isPrimed ) {
70 [self setString: lastValue];
71 [self setPrimed: NO];
72 }
73 [super resignFirstResponder];
74 }
75 - (void)fireBindingChanged
76 {
77 id delegate = [self delegate];
78 if( delegate != nil && [delegate respondsToSelector:@selector(textDidChange:)] ) {
79 [delegate textDidChange: [NSNotification notificationWithName: NSTextDidChangeNotification object: self]];
80 }
81 }
83 - (void)updateKeysym: (const gchar *)sym
84 {
85 if( sym != NULL ) {
86 [self setString: [NSString stringWithCString: sym]];
87 [self setPrimed: NO];
88 [self fireBindingChanged];
89 }
90 }
91 - (void)keyPressed: (int)keycode
92 {
93 gchar *keysym = input_keycode_to_keysym(NULL, keycode);
94 if( keysym != NULL ) {
95 [self updateKeysym: keysym];
96 g_free(keysym);
97 }
98 }
99 - (void)insertText:(id)string
100 {
101 // Do nothing
102 }
103 - (void)mouseDown: (NSEvent *)event
104 {
105 [self setPrimed: YES];
106 [super mouseDown: event];
107 }
108 - (void)keyDown: (NSEvent *) event
109 {
110 NSString *chars = [event characters];
111 if( isPrimed ) {
112 if( chars != NULL && [chars length] == 1 && [chars characterAtIndex: 0] == 27 ) {
113 // Escape char = abort change
114 [self setString: lastValue];
115 [self setPrimed: NO];
116 } else {
117 [self keyPressed: ([event keyCode]+1)];
118 }
119 } else {
120 if( chars != NULL && [chars length] == 1 ) {
121 int ch = [chars characterAtIndex: 0];
122 switch( ch ) {
123 case 0x7F:
124 [self setString: @""];
125 [self fireBindingChanged];
126 break;
127 case '\r':
128 [self setPrimed: YES];
129 break;
130 default:
131 [super keyDown: event];
132 break;
133 }
134 } else {
135 [super keyDown: event];
136 }
137 }
138 }
139 - (void)flagsChanged: (NSEvent *) event
140 {
141 if( isPrimed ) {
142 [self keyPressed: ([event keyCode]+1)];
143 }
144 [super flagsChanged: event];
145 }
146 @end
148 static void cocoa_config_keysym_hook(void *data, const gchar *keysym)
149 {
150 KeyBindingEditor *editor = (KeyBindingEditor *)data;
151 [editor updateKeysym: keysym];
152 }
155 @implementation KeyBindingField
156 @end
158 /*************************** Key-binding sub-view ***********************/
160 #define MAX_KEY_BINDINGS 32
162 @interface ControllerKeyBindingView : NSView
163 {
164 maple_device_t device;
165 KeyBindingField *field[MAX_KEY_BINDINGS][2];
166 }
167 - (id)initWithFrame: (NSRect)frameRect;
168 - (void)setDevice: (maple_device_t)device;
169 @end
171 @implementation ControllerKeyBindingView
172 - (id)initWithFrame: (NSRect)frameRect
173 {
174 if( [super initWithFrame: frameRect] == nil ) {
175 return nil;
176 } else {
177 device = NULL;
178 return self;
179 }
180 }
181 - (BOOL)isFlipped
182 {
183 return YES;
184 }
185 - (void)removeSubviews
186 {
187 [[self subviews] makeObjectsPerformSelector: @selector(removeFromSuperview)];
188 }
189 - (void)controlTextDidChange: (NSNotification *)notify
190 {
191 int binding = [[notify object] tag];
192 NSString *val1 = [field[binding][0] stringValue];
193 NSString *val2 = [field[binding][1] stringValue];
194 char buf[ [val1 length] + [val2 length] + 2 ];
195 const gchar *p = NULL;
197 if( [val1 length] == 0 ) {
198 if( [val2 length] != 0 ) {
199 p = [val2 UTF8String];
200 }
201 } else if( [val2 length] == 0 ) {
202 p = [val1 UTF8String];
203 } else {
204 sprintf( buf, "%s,%s", [val1 UTF8String], [val2 UTF8String] );
205 p = buf;
206 }
207 maple_set_device_config_value( device, binding, p );
208 lxdream_save_config();
209 }
210 - (void)setDevice: (maple_device_t)newDevice
211 {
212 device = newDevice;
213 [self removeSubviews];
214 if( device != NULL ) {
215 lxdream_config_entry_t config = maple_get_device_config(device);
216 if( config != NULL ) {
217 int count, i, y, x;
219 for( count=0; config[count].key != NULL; count++ );
220 x = TEXT_GAP;
221 NSSize size = NSMakeSize(85*3+TEXT_GAP*4, count*(TEXT_HEIGHT+TEXT_GAP)+TEXT_GAP);
222 [self setFrameSize: size];
223 [self scrollRectToVisible: NSMakeRect(0,0,1,1)];
224 y = TEXT_GAP;
225 for( i=0; config[i].key != NULL; i++ ) {
226 NSRect frame = NSMakeRect(x, y + 2, 85, LABEL_HEIGHT);
227 NSTextField *label = cocoa_gui_add_label(self, NS_(config[i].label), frame);
228 [label setAlignment: NSRightTextAlignment];
230 frame = NSMakeRect( x + 85 + TEXT_GAP, y, 85, TEXT_HEIGHT);
231 field[i][0] = [[KeyBindingField alloc] initWithFrame: frame];
232 [field[i][0] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
233 [field[i][0] setTag: i];
234 [field[i][0] setDelegate: self];
235 [self addSubview: field[i][0]];
237 frame = NSMakeRect( x + (85*2) + (TEXT_GAP*2), y, 85, TEXT_HEIGHT);
238 field[i][1] = [[KeyBindingField alloc] initWithFrame: frame];
239 [field[i][1] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
240 [field[i][1] setTag: i];
241 [field[i][1] setDelegate: self];
242 [self addSubview: field[i][1]];
244 if( config[i].value != NULL ) {
245 gchar **parts = g_strsplit(config[i].value,",",3);
246 if( parts[0] != NULL ) {
247 [field[i][0] setStringValue: [NSString stringWithCString: parts[0]]];
248 if( parts[1] != NULL ) {
249 [field[i][1] setStringValue: [NSString stringWithCString: parts[1]]];
250 }
251 }
252 g_strfreev(parts);
253 }
255 y += (TEXT_HEIGHT + TEXT_GAP);
256 }
257 } else {
258 [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
259 }
260 } else {
261 [self setFrameSize: NSMakeSize(100,TEXT_HEIGHT+TEXT_GAP) ];
262 }
263 }
264 @end
266 /*************************** Top-level controller pane ***********************/
268 @interface LxdreamPrefsControllerPane: LxdreamPrefsPane
269 {
270 struct maple_device *save_controller[4];
271 NSButton *radio[4];
272 ControllerKeyBindingView *key_bindings;
273 }
274 + (LxdreamPrefsControllerPane *)new;
275 @end
277 @implementation LxdreamPrefsControllerPane
278 + (LxdreamPrefsControllerPane *)new
279 {
280 return [[LxdreamPrefsControllerPane alloc] initWithFrame: NSMakeRect(0,0,600,400)];
281 }
282 - (id)initWithFrame: (NSRect)frameRect
283 {
284 if( [super initWithFrame: frameRect title: NS_("Controllers")] == nil ) {
285 return nil;
286 } else {
287 const struct maple_device_class **devices = maple_get_device_classes();
288 char buf[16];
289 int i,j;
290 int y = [self contentHeight] - TEXT_HEIGHT - TEXT_GAP;
292 NSBox *rule = [[NSBox alloc] initWithFrame:
293 NSMakeRect(210+(TEXT_GAP*3), 1, 1, [self contentHeight] + TEXT_GAP - 2)];
294 [rule setAutoresizingMask: (NSViewMaxXMargin|NSViewHeightSizable)];
295 [rule setBoxType: NSBoxSeparator];
296 [self addSubview: rule];
298 NSRect bindingFrame = NSMakeRect(210+(TEXT_GAP*4), 0,
299 frameRect.size.width - (210+(TEXT_GAP*4)), [self contentHeight] + TEXT_GAP );
300 NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: bindingFrame];
301 key_bindings = [[ControllerKeyBindingView alloc] initWithFrame: bindingFrame ];
302 [scrollView setAutoresizingMask: (NSViewWidthSizable|NSViewHeightSizable)];
303 [scrollView setDocumentView: key_bindings];
304 [scrollView setDrawsBackground: NO];
305 [scrollView setHasVerticalScroller: YES];
306 [scrollView setAutohidesScrollers: YES];
308 [self addSubview: scrollView];
309 [key_bindings setDevice: maple_get_device(0,0)];
311 for( i=0; i<MAX_DEVICES; i++ ) {
312 int x = TEXT_GAP;
313 save_controller[i] = NULL;
314 maple_device_t device = maple_get_device(i,0);
316 snprintf( buf, sizeof(buf), _("Slot %d."), i );
317 radio[i] = [[NSButton alloc] initWithFrame: NSMakeRect( x, y, 60, TEXT_HEIGHT )];
318 [radio[i] setTitle: [NSString stringWithUTF8String: buf]];
319 [radio[i] setTag: i];
320 [radio[i] setButtonType: NSRadioButton];
321 [radio[i] setAlignment: NSRightTextAlignment];
322 [radio[i] setTarget: self];
323 [radio[i] setAction: @selector(radioChanged:)];
324 [radio[i] setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
325 [self addSubview: radio[i]];
326 x += 60 + TEXT_GAP;
328 NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame: NSMakeRect(x,y,150,TEXT_HEIGHT)
329 pullsDown: NO];
330 [popup addItemWithTitle: NS_("<empty>")];
331 [popup setAutoresizingMask: (NSViewMinYMargin|NSViewMaxXMargin)];
332 [[popup itemAtIndex: 0] setTag: 0];
333 for( j=0; devices[j] != NULL; j++ ) {
334 [popup addItemWithTitle: [NSString stringWithUTF8String: devices[j]->name]];
335 if( device != NULL && device->device_class == devices[j] ) {
336 [popup selectItemAtIndex: (j+1)];
337 }
338 [[popup itemAtIndex: (j+1)] setTag: (j+1)];
339 }
340 [popup setTarget: self];
341 [popup setAction: @selector(deviceChanged:)];
342 [popup setTag: i];
343 [self addSubview: popup];
344 y -= (TEXT_HEIGHT+TEXT_GAP);
345 }
347 [radio[0] setState: NSOnState];
348 return self;
349 }
350 }
351 - (void)radioChanged: (id)sender
352 {
353 int slot = [sender tag];
354 int i;
355 for( i=0; i<MAX_DEVICES; i++ ) {
356 if( i != slot ) {
357 [radio[i] setState: NSOffState];
358 }
359 }
360 [key_bindings setDevice: maple_get_device(slot,0)];
361 }
362 - (void)deviceChanged: (id)sender
363 {
364 int slot = [sender tag];
365 int new_device_idx = [sender indexOfSelectedItem] - 1, i;
366 maple_device_class_t new_device_class = NULL;
368 for( i=0; i<MAX_DEVICES; i++ ) {
369 if( i == slot ) {
370 [radio[i] setState: NSOnState];
371 } else {
372 [radio[i] setState: NSOffState];
373 }
374 }
376 maple_device_t current = maple_get_device(slot,0);
377 maple_device_t new_device = NULL;
378 if( new_device_idx != -1 ) {
379 new_device_class = maple_get_device_classes()[new_device_idx];
380 }
381 if( current == NULL ? new_device_class == NULL : current->device_class == new_device_class ) {
382 // No change
383 [key_bindings setDevice: current];
384 return;
385 }
386 if( current != NULL && current->device_class == &controller_class ) {
387 save_controller[slot] = current->clone(current);
388 }
389 if( new_device_class == NULL ) {
390 maple_detach_device(slot,0);
391 } else {
392 if( new_device_class == &controller_class && save_controller[slot] != NULL ) {
393 new_device = save_controller[slot];
394 save_controller[slot] = NULL;
395 } else {
396 new_device = maple_new_device( new_device_class->name );
397 }
398 maple_attach_device(new_device,slot,0);
399 }
400 [key_bindings setDevice: maple_get_device(slot,0)];
401 lxdream_save_config();
402 }
403 @end
405 NSView *cocoa_gui_create_prefs_controller_pane()
406 {
407 return [LxdreamPrefsControllerPane new];
408 }
.