Add support for horizontal directions to scrolling. Rework UI to make the relationshi...
[enjoyable.git] / Classes / NJOutputController.m
1 //
2 // NJOutputController.m
3 // Enjoy
4 //
5 // Created by Sam McCall on 5/05/09.
6 //
7
8 #import "NJOutputController.h"
9
10 #import "NJMappingsController.h"
11 #import "NJMapping.h"
12 #import "NJInput.h"
13 #import "NJEvents.h"
14 #import "NJDeviceController.h"
15 #import "NJKeyInputField.h"
16 #import "NJOutputMapping.h"
17 #import "NJOutputController.h"
18 #import "NJOutputKeyPress.h"
19 #import "NJOutputMouseButton.h"
20 #import "NJOutputMouseMove.h"
21 #import "NJOutputMouseScroll.h"
22
23 @implementation NJOutputController
24
25 - (id)init {
26 if ((self = [super init])) {
27 [NSNotificationCenter.defaultCenter
28 addObserver:self
29 selector:@selector(mappingListDidChange:)
30 name:NJEventMappingListChanged
31 object:nil];
32 }
33 return self;
34 }
35
36 - (void)dealloc {
37 [NSNotificationCenter.defaultCenter removeObserver:self];
38 }
39
40 - (void)cleanUpInterface {
41 NSInteger row = radioButtons.selectedRow;
42
43 if (row != 1) {
44 keyInput.keyCode = NJKeyInputFieldEmpty;
45 [keyInput resignIfFirstResponder];
46 }
47
48 if (row != 2) {
49 [mappingPopup selectItemAtIndex:-1];
50 [mappingPopup resignIfFirstResponder];
51 } else if (!mappingPopup.selectedItem)
52 [mappingPopup selectItemAtIndex:0];
53
54 if (row != 3) {
55 mouseDirSelect.selectedSegment = -1;
56 mouseSpeedSlider.floatValue = mouseSpeedSlider.minValue;
57 [mouseDirSelect resignIfFirstResponder];
58 } else {
59 if (mouseDirSelect.selectedSegment == -1)
60 mouseDirSelect.selectedSegment = 0;
61 if (!mouseSpeedSlider.floatValue)
62 mouseSpeedSlider.floatValue = 10;
63 }
64
65 if (row != 4) {
66 mouseBtnSelect.selectedSegment = -1;
67 [mouseBtnSelect resignIfFirstResponder];
68 } else if (mouseBtnSelect.selectedSegment == -1)
69 mouseBtnSelect.selectedSegment = 0;
70
71 if (row != 5) {
72 scrollDirSelect.selectedSegment = -1;
73 scrollSpeedSlider.floatValue = scrollSpeedSlider.minValue;
74 smoothCheck.state = NSOffState;
75 [scrollDirSelect resignIfFirstResponder];
76 [scrollSpeedSlider resignIfFirstResponder];
77 [smoothCheck resignIfFirstResponder];
78 } else {
79 if (scrollDirSelect.selectedSegment == -1)
80 scrollDirSelect.selectedSegment = 0;
81 }
82
83 }
84
85 - (IBAction)radioChanged:(NSView *)sender {
86 [sender.window makeFirstResponder:sender];
87 if (radioButtons.selectedRow == 1)
88 [keyInput.window makeFirstResponder:keyInput];
89 [self commit];
90 }
91
92 - (void)keyInputField:(NJKeyInputField *)keyInput didChangeKey:(CGKeyCode)keyCode {
93 [radioButtons selectCellAtRow:1 column:0];
94 [radioButtons.window makeFirstResponder:radioButtons];
95 [self commit];
96 }
97
98 - (void)keyInputFieldDidClear:(NJKeyInputField *)keyInput {
99 [radioButtons selectCellAtRow:0 column:0];
100 [self commit];
101 }
102
103 - (void)mappingChosen:(id)sender {
104 [radioButtons selectCellAtRow:2 column:0];
105 [mappingPopup.window makeFirstResponder:mappingPopup];
106 [self commit];
107 }
108
109 - (void)mdirChanged:(NSView *)sender {
110 [radioButtons selectCellAtRow:3 column:0];
111 [sender.window makeFirstResponder:sender];
112 [self commit];
113 }
114
115 - (void)mouseSpeedChanged:(NSSlider *)sender {
116 [radioButtons selectCellAtRow:3 column:0];
117 [sender.window makeFirstResponder:sender];
118 [self commit];
119 }
120
121 - (void)mbtnChanged:(NSView *)sender {
122 [radioButtons selectCellAtRow:4 column:0];
123 [sender.window makeFirstResponder:sender];
124 [self commit];
125 }
126
127 - (void)sdirChanged:(NSView *)sender {
128 [radioButtons selectCellAtRow:5 column:0];
129 [sender.window makeFirstResponder:sender];
130 [self commit];
131 }
132
133 - (void)scrollSpeedChanged:(NSSlider *)sender {
134 [radioButtons selectCellAtRow:5 column:0];
135 [sender.window makeFirstResponder:sender];
136 [self commit];
137 }
138
139 - (IBAction)scrollTypeChanged:(NSButton *)sender {
140 [radioButtons selectCellAtRow:5 column:0];
141 [sender.window makeFirstResponder:sender];
142 if (sender.state == NSOnState) {
143 scrollSpeedSlider.floatValue = (scrollSpeedSlider.maxValue - scrollSpeedSlider.minValue) / 2;
144 [scrollSpeedSlider setEnabled:YES];
145 } else {
146 scrollSpeedSlider.floatValue = scrollSpeedSlider.minValue;
147 [scrollSpeedSlider setEnabled:NO];
148 }
149 [self commit];
150 }
151
152 - (NJOutput *)currentOutput {
153 return mappingsController.currentMapping[inputController.selectedInput];
154 }
155
156 - (NJOutput *)makeOutput {
157 switch (radioButtons.selectedRow) {
158 case 0:
159 return nil;
160 case 1:
161 if (keyInput.hasKeyCode) {
162 NJOutputKeyPress *k = [[NJOutputKeyPress alloc] init];
163 k.vk = keyInput.keyCode;
164 return k;
165 } else {
166 return nil;
167 }
168 break;
169 case 2: {
170 NJOutputMapping *c = [[NJOutputMapping alloc] init];
171 c.mapping = mappingsController[mappingPopup.indexOfSelectedItem];
172 return c;
173 }
174 case 3: {
175 NJOutputMouseMove *mm = [[NJOutputMouseMove alloc] init];
176 mm.axis = mouseDirSelect.selectedSegment;
177 mm.speed = mouseSpeedSlider.floatValue;
178 return mm;
179 }
180 case 4: {
181 NJOutputMouseButton *mb = [[NJOutputMouseButton alloc] init];
182 mb.button = [mouseBtnSelect.cell tagForSegment:mouseBtnSelect.selectedSegment];
183 return mb;
184 }
185 case 5: {
186 NJOutputMouseScroll *ms = [[NJOutputMouseScroll alloc] init];
187 ms.direction = [scrollDirSelect.cell tagForSegment:scrollDirSelect.selectedSegment];
188 ms.speed = scrollSpeedSlider.floatValue;
189 ms.smooth = smoothCheck.state == NSOnState;
190 return ms;
191 }
192 default:
193 return nil;
194 }
195 }
196
197 - (void)commit {
198 [self cleanUpInterface];
199 mappingsController.currentMapping[inputController.selectedInput] = [self makeOutput];
200 [mappingsController save];
201 }
202
203 - (BOOL)enabled {
204 return [radioButtons isEnabled];
205 }
206
207 - (void)setEnabled:(BOOL)enabled {
208 [radioButtons setEnabled:enabled];
209 [keyInput setEnabled:enabled];
210 [mappingPopup setEnabled:enabled];
211 [mouseDirSelect setEnabled:enabled];
212 [mouseSpeedSlider setEnabled:enabled];
213 [mouseBtnSelect setEnabled:enabled];
214 [scrollDirSelect setEnabled:enabled];
215 [smoothCheck setEnabled:enabled];
216 [scrollSpeedSlider setEnabled:enabled && smoothCheck.isEnabled];
217 }
218
219 - (void)loadOutput:(NJOutput *)output forInput:(NJInput *)input {
220 if (!input) {
221 self.enabled = NO;
222 title.stringValue = @"";
223 } else {
224 self.enabled = YES;
225 NSString *inpFullName = input.name;
226 for (id <NJInputPathElement> cur = input.base; cur; cur = cur.base) {
227 inpFullName = [[NSString alloc] initWithFormat:@"%@ > %@", cur.name, inpFullName];
228 }
229 title.stringValue = inpFullName;
230 }
231
232 if ([output isKindOfClass:NJOutputKeyPress.class]) {
233 [radioButtons selectCellAtRow:1 column:0];
234 keyInput.keyCode = [(NJOutputKeyPress*)output vk];
235 } else if ([output isKindOfClass:NJOutputMapping.class]) {
236 [radioButtons selectCellAtRow:2 column:0];
237 NSMenuItem *item = [mappingPopup itemWithRepresentedObject:[(NJOutputMapping *)output mapping]];
238 [mappingPopup selectItem:item];
239 if (!item)
240 [radioButtons selectCellAtRow:self.enabled ? 0 : -1 column:0];
241 }
242 else if ([output isKindOfClass:NJOutputMouseMove.class]) {
243 [radioButtons selectCellAtRow:3 column:0];
244 mouseDirSelect.selectedSegment = [(NJOutputMouseMove *)output axis];
245 mouseSpeedSlider.floatValue = [(NJOutputMouseMove *)output speed];
246 }
247 else if ([output isKindOfClass:NJOutputMouseButton.class]) {
248 [radioButtons selectCellAtRow:4 column:0];
249 [mouseBtnSelect selectSegmentWithTag:[(NJOutputMouseButton *)output button]];
250 }
251 else if ([output isKindOfClass:NJOutputMouseScroll.class]) {
252 [radioButtons selectCellAtRow:5 column:0];
253 int direction = [(NJOutputMouseScroll *)output direction];
254 float speed = [(NJOutputMouseScroll *)output speed];
255 BOOL smooth = [(NJOutputMouseScroll *)output smooth];
256 [scrollDirSelect selectSegmentWithTag:direction];
257 scrollSpeedSlider.floatValue = speed;
258 smoothCheck.state = smooth ? NSOnState : NSOffState;
259 [scrollSpeedSlider setEnabled:smooth];
260 } else {
261 [radioButtons selectCellAtRow:self.enabled ? 0 : -1 column:0];
262 }
263 [self cleanUpInterface];
264 }
265
266 - (void)loadCurrent {
267 [self loadOutput:self.currentOutput forInput:inputController.selectedInput];
268 }
269
270 - (void)focusKey {
271 if (radioButtons.selectedRow <= 1)
272 [keyInput.window makeFirstResponder:keyInput];
273 else
274 [keyInput resignIfFirstResponder];
275 }
276
277 - (void)mappingListDidChange:(NSNotification *)note {
278 NSArray *mappings = note.object;
279 NJMapping *current = mappingPopup.selectedItem.representedObject;
280 [mappingPopup.menu removeAllItems];
281 for (NJMapping *mapping in mappings) {
282 NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:mapping.name
283 action:@selector(mappingChosen:)
284 keyEquivalent:@""];
285 item.target = self;
286 item.representedObject = mapping;
287 [mappingPopup.menu addItem:item];
288 }
289 [mappingPopup selectItemWithRepresentedObject:current];
290 }
291
292 @end