00001 /* 00002 * CPResponder.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 @import <Foundation/CPObject.j> 00024 00025 00026 CPDeleteKeyCode = 8; 00027 CPTabKeyCode = 9; 00028 CPReturnKeyCode = 13; 00029 CPEscapeKeyCode = 27; 00030 CPSpaceKeyCode = 32; 00031 CPPageUpKeyCode = 33; 00032 CPPageDownKeyCode = 34; 00033 CPLeftArrowKeyCode = 37; 00034 CPUpArrowKeyCode = 38; 00035 CPRightArrowKeyCode = 39; 00036 CPDownArrowKeyCode = 40; 00037 00044 @implementation CPResponder : CPObject 00045 { 00046 CPMenu _menu; 00047 CPResponder _nextResponder; 00048 } 00049 00050 // Changing the first responder 00054 - (BOOL)acceptsFirstResponder 00055 { 00056 return NO; 00057 } 00058 00064 - (BOOL)becomeFirstResponder 00065 { 00066 return YES; 00067 } 00068 00073 - (BOOL)resignFirstResponder 00074 { 00075 return YES; 00076 } 00077 00078 // Setting the next responder 00083 - (void)setNextResponder:(CPResponder)aResponder 00084 { 00085 _nextResponder = aResponder; 00086 } 00087 00091 - (CPResponder)nextResponder 00092 { 00093 return _nextResponder; 00094 } 00095 00100 - (void)interpretKeyEvents:(CPArray)events 00101 { 00102 var index = 0, 00103 count = [events count]; 00104 00105 for (; index < count; ++index) 00106 { 00107 var event = events[index]; 00108 00109 switch([event keyCode]) 00110 { 00111 case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)]; 00112 break; 00113 case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)]; 00114 break; 00115 case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)]; 00116 break; 00117 case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)]; 00118 break; 00119 case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)]; 00120 break; 00121 case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)]; 00122 break; 00123 case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)]; 00124 break; 00125 case CPReturnKeyCode: 00126 case 3: [self doCommandBySelector:@selector(insertLineBreak:)]; 00127 break; 00128 00129 case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)]; 00130 break; 00131 00132 case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask; 00133 00134 if (!shift) 00135 [self doCommandBySelector:@selector(insertTab:)]; 00136 else 00137 [self doCommandBySelector:@selector(insertBackTab:)]; 00138 00139 break; 00140 00141 default: [self insertText:[event characters]]; 00142 } 00143 } 00144 } 00145 00150 - (void)mouseDown:(CPEvent)anEvent 00151 { 00152 [_nextResponder performSelector:_cmd withObject:anEvent]; 00153 } 00154 00160 - (void)mouseDragged:(CPEvent)anEvent 00161 { 00162 [_nextResponder performSelector:_cmd withObject:anEvent]; 00163 } 00164 00169 - (void)mouseUp:(CPEvent)anEvent 00170 { 00171 [_nextResponder performSelector:_cmd withObject:anEvent]; 00172 } 00173 00178 - (void)mouseMoved:(CPEvent)anEvent 00179 { 00180 [_nextResponder performSelector:_cmd withObject:anEvent]; 00181 } 00182 00183 - (void)mouseEntered:(CPEvent)anEvent 00184 { 00185 [_nextResponder performSelector:_cmd withObject:anEvent]; 00186 } 00187 00192 - (void)mouseExited:(CPEvent)anEvent 00193 { 00194 [_nextResponder performSelector:_cmd withObject:anEvent]; 00195 } 00196 00201 - (void)scrollWheel:(CPEvent)anEvent 00202 { 00203 [_nextResponder performSelector:_cmd withObject:anEvent]; 00204 } 00205 00210 - (void)keyDown:(CPEvent)anEvent 00211 { 00212 [_nextResponder performSelector:_cmd withObject:anEvent]; 00213 } 00214 00219 - (void)keyUp:(CPEvent)anEvent 00220 { 00221 [_nextResponder performSelector:_cmd withObject:anEvent]; 00222 } 00223 00224 /* 00225 FIXME This description is bad. 00226 Based on \c anEvent, the receiver should simulate the event. 00227 @param anEvent the event to simulate 00228 @return \c YES if the event receiver simulated the event 00229 */ 00230 - (BOOL)performKeyEquivalent:(CPEvent)anEvent 00231 { 00232 return NO; 00233 } 00234 00235 // Action Methods 00240 - (void)insertLineBreak:(id)aSender 00241 { 00242 [self insertNewline:aSender]; 00243 } 00244 00249 - (void)insertNewline:(id)aSender 00250 { 00251 [[self nextResponder] insertNewline:aSender]; 00252 } 00253 00254 - (void)cancel:(id)sender 00255 { 00256 } 00257 00258 - (void)insertTab:(id)sender 00259 { 00260 } 00261 00262 - (void)insertBackTab:(id)sender 00263 { 00264 } 00265 00270 - (void)insertText:(CPString)aString 00271 { 00272 } 00273 00274 // Dispatch methods 00280 - (void)doCommandBySelector:(SEL)aSelector 00281 { 00282 if ([self respondsToSelector:aSelector]) 00283 [self performSelector:aSelector]; 00284 else 00285 [_nextResponder doCommandBySelector:aSelector]; 00286 } 00287 00295 - (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject 00296 { 00297 if([self respondsToSelector:aSelector]) 00298 { 00299 [self performSelector:aSelector withObject:anObject]; 00300 00301 return YES; 00302 } 00303 00304 return [_nextResponder tryToPerform:aSelector with:anObject]; 00305 } 00306 00307 // Managing a Responder's menu 00308 00309 - (void)setMenu:(CPMenu)aMenu 00310 { 00311 _menu = aMenu; 00312 } 00313 00314 - (CPMenu)menu 00315 { 00316 return _menu; 00317 } 00318 00319 // Getting the Undo Manager 00323 - (CPUndoManager)undoManager 00324 { 00325 return [_nextResponder performSelector:_cmd]; 00326 } 00327 00328 // Terminating the responder chain 00333 - (void)noResponderFor:(SEL)anEventSelector 00334 { 00335 } 00336 00337 @end 00338 00339 var CPResponderNextResponderKey = @"CPResponderNextResponderKey"; 00340 00341 @implementation CPResponder (CPCoding) 00342 00348 - (id)initWithCoder:(CPCoder)aCoder 00349 { 00350 self = [super init]; 00351 00352 if (self) 00353 _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; 00354 00355 return self; 00356 } 00357 00362 - (void)encodeWithCoder:(CPCoder)aCoder 00363 { 00364 // This will come out nil on the other side with decodeObjectForKey: 00365 if (_nextResponder !== nil) 00366 [aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey]; 00367 } 00368 00369 @end