From 44f508660018b23b8901a4b4b9430a05cbaf9fe0 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 29 May 2010 03:10:15 -0400 Subject: [PATCH 01/61] Key equivalents for CPButton. --- AppKit/CPButton.j | 74 ++++++++++++++ AppKit/CPEvent.j | 54 ++++++---- AppKit/CPWindow/CPWindow.j | 190 ++++++++++++++++++------------------ Tests/AppKit/CPButtonTest.j | 67 +++++++++++++ 4 files changed, 271 insertions(+), 114 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 57a105bd5..59d33c8c7 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -99,6 +99,9 @@ CPButtonStateMixed = CPThemeState("mixed"); // NS-style Display Properties CPBezelStyle _bezelStyle; CPControlSize _controlSize; + + CPString _keyEquivalent; + unsigned _keyEquivalentModifierMask; } + (id)buttonWithTitle:(CPString)aTitle @@ -142,6 +145,9 @@ CPButtonStateMixed = CPThemeState("mixed"); _controlSize = CPRegularControlSize; + _keyEquivalent = ""; + _keyEquivalentModifierMask = 0; + // [self setBezelStyle:CPRoundRectBezelStyle]; [self setBordered:YES]; } @@ -555,6 +561,74 @@ CPButtonStateMixed = CPThemeState("mixed"); return [self hasThemeState:CPThemeStateBordered]; } +/*! + Sets the keyboard shortcut for this button + @param aString the keyboard shortcut as a string or a key code +*/ +- (void)setKeyEquivalent:(CPString)aString +{ + _keyEquivalent = aString || @""; +} + +/*! + Returns the keyboard shortcut for this button +*/ +- (CPString)keyEquivalent +{ + return _keyEquivalent; +} + +/*! + Returns the mask used with this button's key equivalent. +*/ +- (void)setKeyEquivalentModifierMask:(unsigned)aMask +{ + _keyEquivalentModifierMask = aMask; +} + +/*! + Sets the mask to be used with this button's key equivalent. +*/ +- (unsigned)keyEquivalentModifierMask +{ + return _keyEquivalentModifierMask; +} + +/*! + Checks the button's key equivalent against that in the event, and if they + match simulates a button click. +*/ +- (BOOL)performKeyEquivalent:(CPEvent)anEvent +{ + var characters = [anEvent charactersIgnoringModifiers], + modifierFlags = [anEvent modifierFlags]; + + var modifierMask = [self keyEquivalentModifierMask], + keyEquivalent = [self keyEquivalent], + isKeyCodeEquivalent = typeof keyEquivalent === "number"; + + if (!isKeyCodeEquivalent && keyEquivalent === [keyEquivalent uppercaseString]) + modifierMask |= CPShiftKeyMask; + + if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask)) + { + modifierMask |= CPControlKeyMask; + modifierMask &= ~CPCommandKeyMask; + } + + if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== modifierMask) + return NO; + + if (!isKeyCodeEquivalent && [characters caseInsensitiveCompare:keyEquivalent] !== CPOrderedSame) + return NO; + + if (isKeyCodeEquivalent && [anEvent keyCode] !== keyEquivalent) + return NO; + + [self performClick:nil]; + return YES; +} + @end @implementation CPButton (NS) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index a60a05114..aa5bb531c 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -41,7 +41,7 @@ CPAppKitDefined = 13; CPSystemDefined = 14; CPApplicationDefined = 15; CPPeriodic = 16; -CPCursorUpdate = 17; +CPCursorUpdate = 17; CPScrollWheel = 22; CPOtherMouseDown = 25; CPOtherMouseUp = 26; @@ -52,8 +52,8 @@ CPTouchStart = 28; CPTouchMove = 29; CPTouchEnd = 30; CPTouchCancel = 31; - - + + CPAlphaShiftKeyMask = 1 << 16; CPShiftKeyMask = 1 << 17; CPControlKeyMask = 1 << 18; @@ -106,7 +106,7 @@ CPDOMEventTouchCancel = "touchcancel"; var _CPEventPeriodicEventPeriod = 0, _CPEventPeriodicEventTimer = nil; -/*! +/*! @ingroup appkit @class CPEvent CPEvent encapsulates the details of a Cappuccino keyboard or mouse event. @@ -155,7 +155,7 @@ var _CPEventPeriodicEventPeriod = 0, characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code { return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags - timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext + timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code]; } @@ -173,7 +173,7 @@ var _CPEventPeriodicEventPeriod = 0, @throws CPInternalInconsistencyException if an invalid event type is provided @return the new mouse event */ -+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags ++ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure { @@ -204,12 +204,12 @@ var _CPEventPeriodicEventPeriod = 0, } /* @ignore */ -- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags +- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure { self = [super init]; - + if (self) { _type = anEventType; @@ -222,7 +222,7 @@ var _CPEventPeriodicEventPeriod = 0, _pressure = aPressure; _window = [CPApp windowWithWindowNumber:aWindowNumber]; } - + return self; } @@ -232,7 +232,7 @@ var _CPEventPeriodicEventPeriod = 0, characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code { self = [super init]; - + if (self) { _type = anEventType; @@ -246,7 +246,7 @@ var _CPEventPeriodicEventPeriod = 0, _keyCode = code; _windowNumber = aWindowNumber; } - + return self; } @@ -256,7 +256,7 @@ var _CPEventPeriodicEventPeriod = 0, subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2 { self = [super init]; - + if (self) { _type = anEventType; @@ -267,7 +267,7 @@ var _CPEventPeriodicEventPeriod = 0, _subtype = aSubtype; _data1 = aData1; _data2 = aData2; - } + } return self; } @@ -448,20 +448,36 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_couldBeKeyEquivalent { // FIXME: More cases? Space? + // FIXME _hasActionKeyCode is basically here to allow setKeyEquivalent 'escape' on a CPButton. return _type === CPKeyDown && - _modifierFlags & (CPCommandKeyMask | CPControlKeyMask) && - [_characters length] > 0; + ((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) && + [_characters length] > 0) || + [self _hasActionKeyCode]); +} + +- (BOOL)_hasActionKeyCode +{ + switch(_keyCode) + { + case CPDeleteKeyCode: + case CPReturnKeyCode: + case CPEscapeKeyCode: + case CPTabKeyCode: + return YES; + default: + return NO; + } } /*! - Generates periodic events every \c aPeriod seconds. + Gene rates periodic events every \c aPeriod seconds. @param aDelay the number of seconds before the first event @param aPeriod the length of time in seconds between successive events */ + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod { _CPEventPeriodicEventPeriod = aPeriod; - + // FIXME: OH TIMERS!!! _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0); } @@ -473,9 +489,9 @@ var _CPEventPeriodicEventPeriod = 0, { if (_CPEventPeriodicEventTimer === nil) return; - + window.clearTimeout(_CPEventPeriodicEventTimer); - + _CPEventPeriodicEventTimer = nil; } diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index a28ecf2a6..00cd3b8de 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -194,13 +194,13 @@ var SHADOW_MARGIN_LEFT = 20.0, SHADOW_MARGIN_TOP = 10.0, SHADOW_MARGIN_BOTTOM = 10.0, SHADOW_DISTANCE = 5.0, - + _CPWindowShadowColor = nil; - + var CPWindowSaveImage = nil, CPWindowSavingImage = nil; -/*! +/*! @ingroup appkit @class CPWindow @@ -213,33 +213,33 @@ var CPWindowSaveImage = nil,

A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.

You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument. - + @par Delegate Methods - + @delegate -(void)windowDidResize:(CPNotification)notification; Sent from the notification center when the window has been resized. @param notification contains information about the resize event - + @delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window; Called to obtain the undo manager for a window @param window the window for which to return the undo manager @return the window's undo manager - + @delegate -(void)windowDidBecomeMain:(CPNotification)notification; Sent from the notification center when the delegate's window becomes the main window. @param notification contains information about the event - + @delegate -(void)windowDidResignMain:(CPNotification)notification; Sent from the notification center when the delegate's window has resigned main window status. @param notification contains information about the event - + @delegate -(void)windowDidResignKey:(CPNotification)notification; Sent from the notification center when the delegate's window has resigned key window status. @param notification contains information about the event - + @delegate -(BOOL)windowShouldClose:(id)window; Called when the user tries to close the window. @param window the window to close @@ -311,12 +311,12 @@ var CPWindowSaveImage = nil, #endif unsigned _autoresizingMask; - + BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; BOOL _isFullPlatformWindow; _CPWindowFullPlatformWindowSession _fullPlatformWindowSession; - + CPDictionary _sheetContext; CPWindow _parentView; BOOL _isSheet; @@ -330,9 +330,9 @@ var CPWindowSaveImage = nil, { if (self != [CPWindow class]) return; - + var bundle = [CPBundle bundleForClass:[CPWindow class]]; - + CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)] } @@ -359,7 +359,7 @@ CPTexturedBackgroundWindowMask - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask { self = [super init]; - + if (self) { var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask]; @@ -393,7 +393,7 @@ CPTexturedBackgroundWindowMask // Set up our window number. _windowNumber = [CPApp._windows count]; CPApp._windows[_windowNumber] = self; - + _styleMask = aStyleMask; [self setLevel:CPNormalWindowLevel]; @@ -408,15 +408,15 @@ CPTexturedBackgroundWindowMask [_windowView setNextResponder:self]; [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask]; - + // Create a generic content view. [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; - + _firstResponder = self; #if PLATFORM(DOM) _DOMElement = document.createElement("div"); - + _DOMElement.style.position = "absolute"; _DOMElement.style.visibility = "visible"; _DOMElement.style.zIndex = 0; @@ -442,7 +442,7 @@ CPTexturedBackgroundWindowMask [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask]; } - + return self; } @@ -660,7 +660,7 @@ CPTexturedBackgroundWindowMask if (shouldAnimate) { var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - + [animation startAnimation]; } else @@ -882,12 +882,12 @@ CPTexturedBackgroundWindowMask { if (_contentView) [_contentView removeFromSuperview]; - + var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); - + _contentView = aView; [_contentView setFrame:[self contentRectForFrameRect:bounds]]; - + [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_windowView addSubview:_contentView]; } @@ -943,24 +943,24 @@ CPTexturedBackgroundWindowMask { if (CGSizeEqualToSize(_minSize, aSize)) return; - + _minSize = CGSizeCreateCopy(aSize); var size = CGSizeMakeCopy([self frame].size), needsFrameChange = NO; - + if (size.width < _minSize.width) { size.width = _minSize.width; needsFrameChange = YES; } - + if (size.height < _minSize.height) { size.height = _minSize.height; needsFrameChange = YES; } - + if (needsFrameChange) [self setFrameSize:size]; } @@ -983,24 +983,24 @@ CPTexturedBackgroundWindowMask { if (CGSizeEqualToSize(_maxSize, aSize)) return; - + _maxSize = CGSizeCreateCopy(aSize); var size = CGSizeMakeCopy([self frame].size), needsFrameChange = NO; - + if (size.width > _maxSize.width) { size.width = _maxSize.width; needsFrameChange = YES; } - + if (size.height > _maxSize.height) { size.height = _maxSize.height; needsFrameChange = YES; } - + if (needsFrameChange) [self setFrameSize:size]; } @@ -1041,10 +1041,10 @@ CPTexturedBackgroundWindowMask if (_hasShadow && !_shadowView) { var bounds = [_windowView bounds]; - - _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, + + _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)]; - + if (!_CPWindowShadowColor) { var bundle = [CPBundle bundleForClass:[CPWindow class]]; @@ -1067,7 +1067,7 @@ CPTexturedBackgroundWindowMask [_shadowView setBackgroundColor:_CPWindowShadowColor]; [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; - + #if PLATFORM(DOM) CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement); #endif @@ -1133,7 +1133,7 @@ CPTexturedBackgroundWindowMask selector:@selector(windowDidBecomeKey:) name:CPWindowDidBecomeKeyNotification object:self]; - + if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) [defaultCenter addObserver:_delegate @@ -1229,7 +1229,7 @@ CPTexturedBackgroundWindowMask if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder]) { _firstResponder = self; - + return NO; } @@ -1282,9 +1282,9 @@ CPTexturedBackgroundWindowMask - (void)setTitle:(CPString)aTitle { _title = aTitle; - + [_windowView setTitle:aTitle]; - + [self _synchronizeMenuBarTitleWithWindowTitle]; } @@ -1536,7 +1536,7 @@ CPTexturedBackgroundWindowMask - (void)makeKeyAndOrderFront:(id)aSender { [self orderFront:self]; - + [self makeKeyWindow]; [self makeMainWindow]; } @@ -1670,9 +1670,9 @@ CPTexturedBackgroundWindowMask { if (_isDocumentEdited == isDocumentEdited) return; - + _isDocumentEdited = isDocumentEdited; - + [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0]; [_windowView setDocumentEdited:isDocumentEdited]; @@ -1690,11 +1690,11 @@ CPTexturedBackgroundWindowMask { if (_isDocumentSaving == isDocumentSaving) return; - + _isDocumentSaving = isDocumentSaving; - + [self _synchronizeSaveMenuWithDocumentSaving]; - + [_windowView windowDidChangeDocumentSaving]; } @@ -1711,16 +1711,16 @@ CPTexturedBackgroundWindowMask var mainMenu = [CPApp mainMenu], index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."]; - + if (index == CPNotFound) return; - + var item = [mainMenu itemAtIndex:index]; - + if (_isDocumentSaving) { CPWindowSaveImage = [item image]; - + [item setTitle:@"Saving..."]; [item setImage:CPWindowSavingImage]; [item setEnabled:NO]; @@ -1810,7 +1810,7 @@ CPTexturedBackgroundWindowMask if (![_delegate windowShouldClose:self]) return; } - + // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true). else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self]) return; @@ -1820,8 +1820,8 @@ CPTexturedBackgroundWindowMask { var index = [documents indexOfObject:[_windowController document]]; - [documents[index] shouldCloseWindowController:_windowController - delegate:self + [documents[index] shouldCloseWindowController:_windowController + delegate:self shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) contextInfo:{documents:[documents copy], visited:0, index:index}]; } @@ -1845,8 +1845,8 @@ CPTexturedBackgroundWindowMask { [windowController setDocument:documents[index]]; - [documents[index] shouldCloseWindowController:_windowController - delegate:self + [documents[index] shouldCloseWindowController:_windowController + delegate:self shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) contextInfo:context]; } @@ -1883,7 +1883,7 @@ CPTexturedBackgroundWindowMask // FIXME: Also check if we can resize and titlebar. if ([self isVisible]) return YES; - + return NO; } @@ -2005,25 +2005,25 @@ CPTexturedBackgroundWindowMask { if (_toolbar === aToolbar) return; - + // If this has an owner, dump it! [[aToolbar _window] setToolbar:nil]; - + // This is no longer out toolbar. [_toolbar _setWindow:nil]; - + _toolbar = aToolbar; - + // THIS is our toolbar. [_toolbar _setWindow:self]; - + [self _noteToolbarChanged]; } - (void)toggleToolbarShown:(id)aSender { var toolbar = [self toolbar]; - + [toolbar setVisible:![toolbar isVisible]]; } @@ -2039,10 +2039,10 @@ CPTexturedBackgroundWindowMask else { newFrame = CGRectMakeCopy([self frame]); - + newFrame.origin = frame.origin; } - + [self setFrame:newFrame]; /* [_windowView setAnimatingToolbar:YES]; @@ -2068,7 +2068,7 @@ CPTexturedBackgroundWindowMask var attachedSheet = [self attachedSheet]; var contentRect = [[self contentView] frame], sheetFrame = CGRectMakeCopy([attachedSheet frame]); - + sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); @@ -2080,8 +2080,8 @@ CPTexturedBackgroundWindowMask { var sheetFrame = [aSheet frame]; - _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; - + _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; + [self _attachSheetWindow:aSheet]; } @@ -2091,12 +2091,12 @@ CPTexturedBackgroundWindowMask var sheetFrame = [aSheet frame], frame = [self frame], sheetContent = [aSheet contentView]; - + [self _setUpMasksForView:sheetContent]; - + aSheet._isSheet = YES; aSheet._parentView = self; - + var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), originy = frame.origin.y + [[self contentView] frame].origin.y, startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), @@ -2104,7 +2104,7 @@ CPTexturedBackgroundWindowMask [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; [CPApp runModalForWindow:aSheet]; - + [aSheet orderFront:self]; [aSheet setFrame:startFrame display:YES animate:NO]; _sheetContext["opened"] = YES; @@ -2112,7 +2112,7 @@ CPTexturedBackgroundWindowMask [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut]; // Should run the main loop here until _isAnimating = FALSE - [aSheet becomeKeyWindow]; + [aSheet becomeKeyWindow]; } /* @ignore */ @@ -2123,9 +2123,9 @@ CPTexturedBackgroundWindowMask endFrame = CGRectMakeCopy(startFrame); endFrame.size.height = 0; - + _sheetContext["frame"] = startFrame; - + var sheetContent = [sheet contentView]; [self _setUpMasksForView:sheetContent]; @@ -2141,27 +2141,27 @@ CPTexturedBackgroundWindowMask return; var sheetContent = [sheet contentView]; - + if (_sheetContext["opened"] === YES) { [self _restoreMasksForView:sheetContent]; return; } - - [CPApp stopModal]; + + [CPApp stopModal]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; [sheet orderOut:self]; var lastFrame = _sheetContext["frame"]; [sheet setFrame:lastFrame]; - + [self _restoreMasksForView:sheetContent]; var delegate = _sheetContext["modalDelegate"], endSelector = _sheetContext["endSelector"]; - if (delegate != nil && endSelector != nil) + if (delegate != nil && endSelector != nil) objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]); _sheetContext = nil; @@ -2173,7 +2173,7 @@ CPTexturedBackgroundWindowMask var views = [aView subviews]; [views addObject:aView]; - + for (var i = 0, count = [views count]; i < count; i++) { var view = [views objectAtIndex:i], @@ -2189,7 +2189,7 @@ CPTexturedBackgroundWindowMask var views = [aView subviews]; [views addObject:aView]; - + for (var i = 0, count = [views count]; i < count; i++) { var view = [views objectAtIndex:i], @@ -2207,7 +2207,7 @@ CPTexturedBackgroundWindowMask { if (_sheetContext === nil) return nil; - + return _sheetContext["sheet"]; } @@ -2288,7 +2288,7 @@ CPTexturedBackgroundWindowMask - (void)recalculateKeyViewLoop { var subviews = []; - + [self _appendSubviewsOf:_contentView toArray:subviews]; var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView], @@ -2296,7 +2296,7 @@ CPTexturedBackgroundWindowMask for (var i=0; i Date: Sat, 29 May 2010 03:10:39 -0400 Subject: [PATCH 02/61] If a button is named "Cancel" in a CPAlert window, give it the 'escape' key equivalent. --- AppKit/CPAlert.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 97a2f1518..589a5d4ee 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -252,6 +252,9 @@ var CPAlertWarningImage, Buttons will be added starting from the right hand side of the \c CPAlert panel. The first button will have the index 0, the second button 1 and so on. + The first button will automatically be given a key equivalent of Return, + and any button titled "Cancel" will be given a key equivalent of Escape. + You really shouldn't need more than 3 buttons. */ - (void)addButtonWithTitle:(CPString)title @@ -271,6 +274,8 @@ var CPAlertWarningImage, if (_buttonCount == 0) [_alertPanel setDefaultButton:button]; + else if ([title lowercaseString] === "cancel") + [button setKeyEquivalent:CPEscapeKeyCode]; _buttonCount++; [_buttons addObject:button]; From c1f16de441a194503cc219777a858c927d456916 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 6 Jun 2010 21:49:28 -0400 Subject: [PATCH 03/61] Defined function and special key constants. --- AppKit/AppKit.j | 1 + AppKit/CPEvent.j | 106 ++++++++++++++++++++++++++++++++++++++++------- AppKit/CPText.j | 42 +++++++++++++++++++ 3 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 AppKit/CPText.j diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index def0987dd..1feb31525 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -76,6 +76,7 @@ @import "CPTabView.j" @import "CPTableColumn.j" @import "CPTableView.j" +@import "CPText.j" @import "CPTextField.j" @import "CPToolbar.j" @import "CPToolbarItem.j" diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index aa5bb531c..ad2111330 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -53,7 +53,6 @@ CPTouchMove = 29; CPTouchEnd = 30; CPTouchCancel = 31; - CPAlphaShiftKeyMask = 1 << 16; CPShiftKeyMask = 1 << 17; CPControlKeyMask = 1 << 18; @@ -87,21 +86,96 @@ CPPeriodicMask = 1 << CPPeriodic; CPScrollWheelMask = 1 << CPScrollWheel; CPAnyEventMask = 0xffffffff; -CPDOMEventDoubleClick = "dblclick", -CPDOMEventMouseDown = "mousedown", -CPDOMEventMouseUp = "mouseup", -CPDOMEventMouseMoved = "mousemove", -CPDOMEventMouseDragged = "mousedrag", -CPDOMEventKeyUp = "keyup", -CPDOMEventKeyDown = "keydown", -CPDOMEventKeyPress = "keypress"; -CPDOMEventCopy = "copy"; -CPDOMEventPaste = "paste"; -CPDOMEventScrollWheel = "mousewheel"; -CPDOMEventTouchStart = "touchstart"; -CPDOMEventTouchMove = "touchmove"; -CPDOMEventTouchEnd = "touchend"; -CPDOMEventTouchCancel = "touchcancel"; +CPUpArrowFunctionKey = "\uF700"; +CPDownArrowFunctionKey = "\uF701"; +CPLeftArrowFunctionKey = "\uF702"; +CPRightArrowFunctionKey = "\uF703"; +CPF1FunctionKey = "\uF704"; +CPF2FunctionKey = "\uF705"; +CPF3FunctionKey = "\uF706"; +CPF4FunctionKey = "\uF707"; +CPF5FunctionKey = "\uF708"; +CPF6FunctionKey = "\uF709"; +CPF7FunctionKey = "\uF70A"; +CPF8FunctionKey = "\uF70B"; +CPF9FunctionKey = "\uF70C"; +CPF10FunctionKey = "\uF70D"; +CPF11FunctionKey = "\uF70E"; +CPF12FunctionKey = "\uF70F"; +CPF13FunctionKey = "\uF710"; +CPF14FunctionKey = "\uF711"; +CPF15FunctionKey = "\uF712"; +CPF16FunctionKey = "\uF713"; +CPF17FunctionKey = "\uF714"; +CPF18FunctionKey = "\uF715"; +CPF19FunctionKey = "\uF716"; +CPF20FunctionKey = "\uF717"; +CPF21FunctionKey = "\uF718"; +CPF22FunctionKey = "\uF719"; +CPF23FunctionKey = "\uF71A"; +CPF24FunctionKey = "\uF71B"; +CPF25FunctionKey = "\uF71C"; +CPF26FunctionKey = "\uF71D"; +CPF27FunctionKey = "\uF71E"; +CPF28FunctionKey = "\uF71F"; +CPF29FunctionKey = "\uF720"; +CPF30FunctionKey = "\uF721"; +CPF31FunctionKey = "\uF722"; +CPF32FunctionKey = "\uF723"; +CPF33FunctionKey = "\uF724"; +CPF34FunctionKey = "\uF725"; +CPF35FunctionKey = "\uF726"; +CPInsertFunctionKey = "\uF727"; +CPDeleteFunctionKey = "\uF728"; +CPHomeFunctionKey = "\uF729"; +CPBeginFunctionKey = "\uF72A"; +CPEndFunctionKey = "\uF72B"; +CPPageUpFunctionKey = "\uF72C"; +CPPageDownFunctionKey = "\uF72D"; +CPPrintScreenFunctionKey = "\uF72E"; +CPScrollLockFunctionKey = "\uF72F"; +CPPauseFunctionKey = "\uF730"; +CPSysReqFunctionKey = "\uF731"; +CPBreakFunctionKey = "\uF732"; +CPResetFunctionKey = "\uF733"; +CPStopFunctionKey = "\uF734"; +CPMenuFunctionKey = "\uF735"; +CPUserFunctionKey = "\uF736"; +CPSystemFunctionKey = "\uF737"; +CPPrintFunctionKey = "\uF738"; +CPClearLineFunctionKey = "\uF739"; +CPClearDisplayFunctionKey = "\uF73A"; +CPInsertLineFunctionKey = "\uF73B"; +CPDeleteLineFunctionKey = "\uF73C"; +CPInsertCharFunctionKey = "\uF73D"; +CPDeleteCharFunctionKey = "\uF73E"; +CPPrevFunctionKey = "\uF73F"; +CPNextFunctionKey = "\uF740"; +CPSelectFunctionKey = "\uF741"; +CPExecuteFunctionKey = "\uF742"; +CPUndoFunctionKey = "\uF743"; +CPRedoFunctionKey = "\uF744"; +CPFindFunctionKey = "\uF745"; +CPHelpFunctionKey = "\uF746"; +CPModeSwitchFunctionKey = "\uF747"; +CPEscapeFunctionKey = "\u001B"; + + +CPDOMEventDoubleClick = "dblclick", +CPDOMEventMouseDown = "mousedown", +CPDOMEventMouseUp = "mouseup", +CPDOMEventMouseMoved = "mousemove", +CPDOMEventMouseDragged = "mousedrag", +CPDOMEventKeyUp = "keyup", +CPDOMEventKeyDown = "keydown", +CPDOMEventKeyPress = "keypress"; +CPDOMEventCopy = "copy"; +CPDOMEventPaste = "paste"; +CPDOMEventScrollWheel = "mousewheel"; +CPDOMEventTouchStart = "touchstart"; +CPDOMEventTouchMove = "touchmove"; +CPDOMEventTouchEnd = "touchend"; +CPDOMEventTouchCancel = "touchcancel"; var _CPEventPeriodicEventPeriod = 0, _CPEventPeriodicEventTimer = nil; diff --git a/AppKit/CPText.j b/AppKit/CPText.j new file mode 100644 index 000000000..e94e59ca8 --- /dev/null +++ b/AppKit/CPText.j @@ -0,0 +1,42 @@ +/* + * CPText.j + * AppKit + * + * Created by Alexander Ljungberg. + * Copyright 2010, WireLoad, LLC. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import "CPView.j" + +CPParagraphSeparatorCharacter = "\u2029"; +CPLineSeparatorCharacter = "\u2028"; +CPTabCharacter = "\u0009"; +CPFormFeedCharacter = "\u000c"; +CPNewlineCharacter = "\u000a"; +CPCarriageReturnCharacter = "\u000d"; +CPEnterCharacter = "\u0003"; +CPBackspaceCharacter = "\u0008"; +CPBackTabCharacter = "\u0019"; +CPDeleteCharacter = "\u007f"; + +@implementation CPText : CPView +{ + +} + +@end + From 381a44148e2f9469d11b52e98b95ff4400578a6a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 7 Jun 2010 01:58:28 -0400 Subject: [PATCH 04/61] Special keys such as backspace and escape can now be used as key equivalents through checking for their unicode representations in [CPEvent characters]. This replaces the earlier raw key code approach. --- AppKit/CPAlert.j | 2 +- AppKit/CPButton.j | 23 ++- AppKit/CPEvent.j | 35 +++-- AppKit/CPResponder.j | 23 +-- AppKit/CPText.j | 2 - AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 174 +++++++++++---------- Tests/AppKit/CPButtonTest.j | 9 +- 7 files changed, 146 insertions(+), 122 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 589a5d4ee..2d1b11ea1 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -275,7 +275,7 @@ var CPAlertWarningImage, if (_buttonCount == 0) [_alertPanel setDefaultButton:button]; else if ([title lowercaseString] === "cancel") - [button setKeyEquivalent:CPEscapeKeyCode]; + [button setKeyEquivalent:CPEscapeFunctionKey]; _buttonCount++; [_buttons addObject:button]; diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 59d33c8c7..efeb2363a 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -562,8 +562,10 @@ CPButtonStateMixed = CPThemeState("mixed"); } /*! - Sets the keyboard shortcut for this button - @param aString the keyboard shortcut as a string or a key code + Sets the keyboard shortcut for this button. For special keys see + CPEvent.j CP...FunctionKey and CPText.j CP...Character. + + @param aString the keyboard shortcut as a string */ - (void)setKeyEquivalent:(CPString)aString { @@ -571,7 +573,7 @@ CPButtonStateMixed = CPThemeState("mixed"); } /*! - Returns the keyboard shortcut for this button + Returns the keyboard shortcut for this button. */ - (CPString)keyEquivalent { @@ -601,13 +603,11 @@ CPButtonStateMixed = CPThemeState("mixed"); - (BOOL)performKeyEquivalent:(CPEvent)anEvent { var characters = [anEvent charactersIgnoringModifiers], - modifierFlags = [anEvent modifierFlags]; + modifierFlags = [anEvent modifierFlags], + modifierMask = [self keyEquivalentModifierMask], + keyEquivalent = [self keyEquivalent]; - var modifierMask = [self keyEquivalentModifierMask], - keyEquivalent = [self keyEquivalent], - isKeyCodeEquivalent = typeof keyEquivalent === "number"; - - if (!isKeyCodeEquivalent && keyEquivalent === [keyEquivalent uppercaseString]) + if (new RegExp("[A-Z]").test(keyEquivalent)) modifierMask |= CPShiftKeyMask; if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask)) @@ -619,10 +619,7 @@ CPButtonStateMixed = CPThemeState("mixed"); if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== modifierMask) return NO; - if (!isKeyCodeEquivalent && [characters caseInsensitiveCompare:keyEquivalent] !== CPOrderedSame) - return NO; - - if (isKeyCodeEquivalent && [anEvent keyCode] !== keyEquivalent) + if ([characters caseInsensitiveCompare:keyEquivalent] !== CPOrderedSame) return NO; [self performClick:nil]; diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index ad2111330..748747ea5 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -522,24 +522,37 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_couldBeKeyEquivalent { // FIXME: More cases? Space? - // FIXME _hasActionKeyCode is basically here to allow setKeyEquivalent 'escape' on a CPButton. return _type === CPKeyDown && ((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) && [_characters length] > 0) || - [self _hasActionKeyCode]); + [self _hasActionCharacter]); } -- (BOOL)_hasActionKeyCode +- (BOOL)_hasActionCharacter { - switch(_keyCode) + var characters = [self characters], + characterCount = [characters length]; + + for(var i=0; i -CPDeleteKeyCode = 8; -CPTabKeyCode = 9; -CPReturnKeyCode = 13; -CPEscapeKeyCode = 27; -CPSpaceKeyCode = 32; -CPPageUpKeyCode = 33; -CPPageDownKeyCode = 34; -CPLeftArrowKeyCode = 37; -CPUpArrowKeyCode = 38; -CPRightArrowKeyCode = 39; -CPDownArrowKeyCode = 40; +CPDeleteKeyCode = 8; +CPTabKeyCode = 9; +CPReturnKeyCode = 13; +CPEscapeKeyCode = 27; +CPSpaceKeyCode = 32; +CPPageUpKeyCode = 33; +CPPageDownKeyCode = 34; +CPLeftArrowKeyCode = 37; +CPUpArrowKeyCode = 38; +CPRightArrowKeyCode = 39; +CPDownArrowKeyCode = 40; +CPDeleteForwardKeyCode = 46; /*! @ingroup appkit diff --git a/AppKit/CPText.j b/AppKit/CPText.j index e94e59ca8..1ef33efe1 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -22,8 +22,6 @@ @import "CPView.j" -CPParagraphSeparatorCharacter = "\u2029"; -CPLineSeparatorCharacter = "\u2028"; CPTabCharacter = "\u0009"; CPFormFeedCharacter = "\u000c"; CPNewlineCharacter = "\u000a"; diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index a0b9403bb..e5bd7a19d 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -19,11 +19,11 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - - + + /* * THIS DOCUMENTATION STOLEN DIRECTLY FROM GOOGLE CLOSURE (licensed under Apache 2) - * + * * Different web browsers have very different keyboard event handling. Most * importantly is that only certain browsers repeat keydown events: * IE, Opera, FF/Win32, and Safari 3 repeat keydown events. @@ -111,6 +111,7 @@ @import @import "CPEvent.j" +@import "CPText.j" @import "CPCompatibility.j" @import "CPDOMWindowLayer.j" @@ -138,10 +139,23 @@ var KeyCodesToPrevent = {}, MozKeyCodeToKeyCodeMap = { 61: 187, // =, equals 59: 186 // ;, semicolon - }; + }, + KeyCodesToFunctionUnicodeMap = {}; KeyCodesToPrevent[CPKeyCodes.A] = YES; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPBackspaceCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; + var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; @implementation CPPlatformWindow (DOM) @@ -306,11 +320,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; keyEventSelector = @selector(keyEvent:), keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector), keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); }, - + mouseEventSelector = @selector(mouseEvent:), mouseEventImplementation = class_getMethodImplementation(theClass, mouseEventSelector), mouseEventCallback = function (anEvent) { mouseEventImplementation(self, nil, anEvent); }, - + contextMenuEventSelector = @selector(contextMenuEvent:), contextMenuEventImplementation = class_getMethodImplementation(theClass, contextMenuEventSelector), contextMenuEventCallback = function (anEvent) { return contextMenuEventImplementation(self, nil, anEvent); }, @@ -318,7 +332,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; scrollEventSelector = @selector(scrollEvent:), scrollEventImplementation = class_getMethodImplementation(theClass, scrollEventSelector), scrollEventCallback = function (anEvent) { scrollEventImplementation(self, nil, anEvent); }, - + touchEventSelector = @selector(touchEvent:), touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector), touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); }; @@ -356,7 +370,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMWindow.addEventListener("DOMMouseScroll", scrollEventCallback, NO); _DOMWindow.addEventListener("mousewheel", scrollEventCallback, NO); - _DOMWindow.addEventListener("resize", resizeEventCallback, NO); + _DOMWindow.addEventListener("resize", resizeEventCallback, NO); _DOMWindow.addEventListener("unload", function() { @@ -400,16 +414,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; theDocument.attachEvent("onmousemove", mouseEventCallback); theDocument.attachEvent("ondblclick", mouseEventCallback); theDocument.attachEvent("oncontextmenu", contextMenuEventCallback); - + theDocument.attachEvent("onkeyup", keyEventCallback); theDocument.attachEvent("onkeydown", keyEventCallback); theDocument.attachEvent("onkeypress", keyEventCallback); - + _DOMWindow.attachEvent("onresize", resizeEventCallback); - + _DOMWindow.onmousewheel = scrollEventCallback; theDocument.onmousewheel = scrollEventCallback; - + _DOMBodyElement.ondrag = function () { return NO; }; _DOMBodyElement.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; }; @@ -596,12 +610,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), windowNumber = [[CPApp keyWindow] windowNumber], - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); - //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist + //We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || KeyCodesToPrevent[aDOMEvent.keyCode]); @@ -618,7 +632,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; else _keyCode = aDOMEvent.keyCode; - var characters = String.fromCharCode(_keyCode).toLowerCase(); + var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase(); overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters; // check for caps lock state @@ -633,7 +647,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; var eligibleForCopyPaste = [self _validateCopyCutOrPasteEvent:aDOMEvent flags:modifierFlags]; - // If this could be a native PASTE event, then we need to further examine it before + // If this could be a native PASTE event, then we need to further examine it before // sending a CPEvent. Select our element to see if anything gets pasted in it. if (characters === "v" && eligibleForCopyPaste) { @@ -646,7 +660,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; isNativePasteEvent = YES; } - // However, of this could be a native COPY event, we need to let the normal event-process take place so it + // However, of this could be a native COPY event, we need to let the normal event-process take place so it // can capture our internal Cappuccino pasteboard. else if ((characters == "c" || characters == "x") && eligibleForCopyPaste) { @@ -668,10 +682,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; //this branch is taken by "remedial" key events // In this state we continue to keypress and send the CPEvent } - + case "keypress": - // we unconditionally break on keypress events with modifiers, - // because we forced the event to be sent on the keydown + // we unconditionally break on keypress events with modifiers, + // because we forced the event to be sent on the keydown if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))) break; @@ -682,7 +696,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _lastKey = keyCode; _charCodes[keyCode] = charCode; - var characters = overrideCharacters || String.fromCharCode(charCode), + var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); // Safari won't send proper capitalization during cmd-key events @@ -700,10 +714,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } break; - + case "keyup": var keyCode = aDOMEvent.keyCode, charCode = _charCodes[keyCode]; - + _keyCode = -1; _lastKey = -1; _charCodes[keyCode] = nil; @@ -714,12 +728,12 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = NO; - var characters = String.fromCharCode(charCode), + var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); - + if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive) characters = charactersIgnoringModifiers; - + event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags timestamp: timestamp windowNumber:windowNumber context:nil characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode]; @@ -867,10 +881,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; { x += element.offsetLeft; y += element.offsetTop; - + } while (element = element.offsetParent); } - + location = _CGPointMake((x + ((aDOMEvent.clientX - 8) / 15)), (y + ((aDOMEvent.clientY - 8) / 15))); } else if (aDOMEvent._overrideLocation) @@ -882,9 +896,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; deltaY = 0.0, windowNumber = 0, timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); StopDOMEventPropagation = YES; @@ -903,31 +917,31 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; deltaX = aDOMEvent.wheelDeltaX / 120.0; deltaY = aDOMEvent.wheelDeltaY / 120.0; } - + else if (aDOMEvent.wheelDelta) deltaY = aDOMEvent.wheelDelta / 120.0; - - else if (aDOMEvent.detail) + + else if (aDOMEvent.detail) deltaY = -aDOMEvent.detail / 3.0; - + else - return; + return; if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues)) { deltaX = -deltaX; deltaY = -deltaY; } - + var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ]; - + event._DOMEvent = aDOMEvent; event._deltaX = deltaX; event._deltaY = deltaY; - + [CPApp sendEvent:event]; - + if (StopDOMEventPropagation) CPDOMEventStop(aDOMEvent, self); @@ -970,7 +984,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1))) { var newEvent = {}; - + switch(aDOMEvent.type) { case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown; @@ -984,27 +998,27 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0]; - + newEvent.clientX = touch.clientX; newEvent.clientY = touch.clientY; - + newEvent.timestamp = aDOMEvent.timestamp; newEvent.target = aDOMEvent.target; - + newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false; - + newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()}; newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()}; - + [self mouseEvent:newEvent]; - + return; } else { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault(); - + if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation(); } @@ -1026,7 +1040,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _overriddenEventType = nil; - return; + return; } var event, @@ -1034,9 +1048,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), windowNumber = 0, - modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | - (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | - (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | + modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | + (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | + (aDOMEvent.altKey ? CPAlternateKeyMask : 0) | (aDOMEvent.metaKey ? CPCommandKeyMask : 0); StopDOMEventPropagation = YES; @@ -1062,7 +1076,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if(_mouseIsDown) { event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0); - + _mouseIsDown = NO; _lastMouseUp = event; _mouseDownWindow = nil; @@ -1075,7 +1089,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; return; } } - + else if (type === "mousedown") { if (sourceElement.tagName === "INPUT" && sourceElement != _DOMFocusElement) @@ -1091,11 +1105,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; //fake a down and up event so that event tracking mode will work correctly [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; [CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags - timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 + timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]]; return; @@ -1116,7 +1130,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _mouseIsDown = YES; _lastMouseDown = event; } - + else // if (type === "mousemove" || type === "drag") { if (_DOMEventMode) @@ -1130,7 +1144,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (event && (!isDragging || !supportsNativeDragAndDrop)) { event._DOMEvent = aDOMEvent; - + [CPApp sendEvent:event]; } @@ -1157,7 +1171,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (!layer) return []; - + return [layer orderedWindows]; } @@ -1170,19 +1184,19 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (!layer && aFlag) { layer = [[CPDOMWindowLayer alloc] initWithLevel:aLevel]; - + [_windowLayers setObject:layer forKey:aLevel]; - // Find the nearest layer. This is similar to a binary search, + // Find the nearest layer. This is similar to a binary search, // only we know we won't find the value. var low = 0, high = _windowLevels.length - 1, middle; - + while (low <= high) { middle = FLOOR((low + high) / 2); - + if (_windowLevels[middle] > aLevel) high = middle - 1; else @@ -1190,7 +1204,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } var insertionIndex = 0; - if (middle !== undefined) + if (middle !== undefined) insertionIndex = _windowLevels[middle] > aLevel ? middle : middle + 1 [_windowLevels insertObject:aLevel atIndex:insertionIndex]; @@ -1198,7 +1212,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _DOMBodyElement.appendChild(layer._DOMElement); } - + return layer; } @@ -1206,11 +1220,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; { [CPPlatform initializeScreenIfNecessary]; - // Grab the appropriate level for the layer, and create it if + // Grab the appropriate level for the layer, and create it if // necessary (if we are not simply removing the window). var layer = [self layerAtLevel:[aWindow level] create:aPlace !== CPWindowOut]; - // Ignore otherWindow, simply remove this window from it's level. + // Ignore otherWindow, simply remove this window from it's level. // If layer is nil, this will be a no-op. if (aPlace === CPWindowOut) return [layer removeWindow:aWindow]; @@ -1263,10 +1277,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; // Skip any windows above or at the dragging level. if (levels[levelCount] >= CPDraggingWindowLevel) continue; - + var windows = [layers objectForKey:levels[levelCount]]._windows, windowCount = windows.length; - + while (windowCount--) { var theWindow = windows[windowCount]; @@ -1278,7 +1292,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; return [theWindow _dragHitTest:aPoint pasteboard:aPasteboard]; } } - + return nil; } @@ -1308,7 +1322,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; - (CPWindow)hitTest:(CPPoint)location { - if (self._only) + if (self._only) return self._only; var levels = _windowLevels, @@ -1324,7 +1338,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; while (windowCount-- && !theWindow) { var candidateWindow = windows[windowCount]; - + if (!candidateWindow._ignoresMouseEvents && [candidateWindow containsPoint:location]) theWindow = candidateWindow; } @@ -1334,10 +1348,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; } /*! - When using command (mac) or control (windows), keys are propagated to the browser by default. + When using command (mac) or control (windows), keys are propagated to the browser by default. To prevent a character key from propagating (to prevent its default action, and instead use it in your own application), use these methods. These methods are additive -- the list builds until you clear it. - + @param characters a list of characters to stop propagating keypresses to the browser. */ + (void)preventCharacterKeysFromPropagating:(CPArray)characters @@ -1418,11 +1432,11 @@ var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation) { if (!aComparisonEvent) return 1; - + var comparisonLocation = [aComparisonEvent locationInWindow]; - - return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && - ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && + + return (aTimestamp - [aComparisonEvent timestamp] < CLICK_TIME_DELTA && + ABS(comparisonLocation.x - aLocation.x) < CLICK_SPACE_DELTA && ABS(comparisonLocation.y - aLocation.y) < CLICK_SPACE_DELTA) ? [aComparisonEvent clickCount] + 1 : 1; } diff --git a/Tests/AppKit/CPButtonTest.j b/Tests/AppKit/CPButtonTest.j index 3ae5e81f8..e922c03b7 100644 --- a/Tests/AppKit/CPButtonTest.j +++ b/Tests/AppKit/CPButtonTest.j @@ -1,6 +1,7 @@ @import @import +@import [CPApplication sharedApplication] @@ -82,14 +83,14 @@ [self assertTrue:wasClicked]; } -- (void)testKeyCodeKeyEquivalent +- (void)testSpecialKeyEquivalent { [button setTarget:self]; [button setAction:@selector(clickMe:)]; - [button setKeyEquivalent:CPEscapeKeyCode]; + [button setKeyEquivalent:CPEscapeFunctionKey]; [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 timestamp:nil windowNumber:nil context:nil - characters:"" charactersIgnoringModifiers:"" isARepeat:NO keyCode:CPSpaceKeyCode]]; + characters:CPDeleteCharacter charactersIgnoringModifiers:CPDeleteCharacter isARepeat:NO keyCode:0]]; [self assertFalse:wasClicked]; [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 timestamp:nil windowNumber:nil context:nil @@ -97,7 +98,7 @@ [self assertFalse:wasClicked]; [button performKeyEquivalent:[CPEvent keyEventWithType:CPKeyUp location:CGPointMakeZero() modifierFlags:0 timestamp:nil windowNumber:nil context:nil - characters:"a" charactersIgnoringModifiers:"a" isARepeat:NO keyCode:CPEscapeKeyCode]]; + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; [self assertTrue:wasClicked]; } From c26ebe0bd28a85676200bf5426f7e1b13c249d98 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 7 Jun 2010 19:01:24 -0400 Subject: [PATCH 05/61] Added support for menu key equivalents such as Escape or Cmd-Delete. Refactored code to recognize key equivalents for reuse between CPMenu and CPButton. Added unit tests for CPMenu key equivalents. --- AppKit/CPButton.j | 19 +--- AppKit/CPEvent.j | 20 ++++ AppKit/CPMenu/CPMenu.j | 112 +++++++++----------- AppKit/CPMenuItem/CPMenuItem.j | 92 ++++++++--------- Tests/AppKit/CPMenuTest.j | 182 +++++++++++++++++++++++++++++++++ 5 files changed, 300 insertions(+), 125 deletions(-) create mode 100644 Tests/AppKit/CPMenuTest.j diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index efeb2363a..b8997986c 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -602,24 +602,7 @@ CPButtonStateMixed = CPThemeState("mixed"); */ - (BOOL)performKeyEquivalent:(CPEvent)anEvent { - var characters = [anEvent charactersIgnoringModifiers], - modifierFlags = [anEvent modifierFlags], - modifierMask = [self keyEquivalentModifierMask], - keyEquivalent = [self keyEquivalent]; - - if (new RegExp("[A-Z]").test(keyEquivalent)) - modifierMask |= CPShiftKeyMask; - - if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask)) - { - modifierMask |= CPControlKeyMask; - modifierMask &= ~CPCommandKeyMask; - } - - if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== modifierMask) - return NO; - - if ([characters caseInsensitiveCompare:keyEquivalent] !== CPOrderedSame) + if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]]) return NO; [self performClick:nil]; diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index 748747ea5..0fca38549 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -519,6 +519,26 @@ var _CPEventPeriodicEventPeriod = 0, return _deltaZ; } +- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask +{ + var characters = [self charactersIgnoringModifiers], + modifierFlags = [self modifierFlags]; + + if (new RegExp("[A-Z]").test(aKeyEquivalent)) + aKeyEquivalentModifierMask |= CPShiftKeyMask; + + if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask)) + { + aKeyEquivalentModifierMask |= CPControlKeyMask; + aKeyEquivalentModifierMask &= ~CPCommandKeyMask; + } + + if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) + return NO; + + return [characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; +} + - (BOOL)_couldBeKeyEquivalent { // FIXME: More cases? Space? diff --git a/AppKit/CPMenu/CPMenu.j b/AppKit/CPMenu/CPMenu.j index 687fb7045..39203dfa7 100644 --- a/AppKit/CPMenu/CPMenu.j +++ b/AppKit/CPMenu/CPMenu.j @@ -50,11 +50,11 @@ var _CPMenuBarVisible = NO, _CPMenuBarAttributes = nil, _CPMenuBarSharedWindow = nil; -/*! +/*! @ingroup appkit @class CPMenu - Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus + Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus and so a heirarchical structure appears. */ @implementation CPMenu : CPObject @@ -69,12 +69,12 @@ var _CPMenuBarVisible = NO, float _minimumWidth; CPMutableArray _items; - + BOOL _autoenablesItems; BOOL _showsStateColumn; id _delegate; - + CPMenuItem _highlightedIndex; _CPMenuWindow _menuWindow; } @@ -95,7 +95,7 @@ var _CPMenuBarVisible = NO, { if (_CPMenuBarVisible === menuBarShouldBeVisible) return; - + _CPMenuBarVisible = menuBarShouldBeVisible; if ([CPPlatform supportsNativeMainMenu]) @@ -105,13 +105,13 @@ var _CPMenuBarVisible = NO, { if (!_CPMenuBarSharedWindow) _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init]; - + [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]]; - + [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle]; [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage]; [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue]; - + [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]]; [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]]; @@ -120,12 +120,12 @@ var _CPMenuBarVisible = NO, [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]]; [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]]; [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]]; - + [_CPMenuBarSharedWindow orderFront:self]; } else [_CPMenuBarSharedWindow orderOut:self]; - + // FIXME: There must be a better way to do this. #if PLATFORM(DOM) [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil]; @@ -159,9 +159,9 @@ var _CPMenuBarVisible = NO, { if (_CPMenuBarAttributes == attributes) return; - + _CPMenuBarAttributes = [attributes copy]; - + var textColor = [attributes objectForKey:@"CPMenuBarTextColor"], titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"], textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"], @@ -169,40 +169,40 @@ var _CPMenuBarVisible = NO, highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"], highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"], highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]; - + if (!textColor && titleColor) [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"]; - + else if (textColor && !titleColor) [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"]; - + else if (!textColor && !titleColor) { [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"]; } - + if (!textShadowColor && titleShadowColor) [_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"]; - + else if (textShadowColor && !titleShadowColor) [_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"]; - + else if (!textShadowColor && !titleShadowColor) { [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"]; } - + if (!highlightColor) [_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"]; - + if (!highlightTextColor) [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"]; - + if (!highlightTextShadowColor) [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"]; - + if (_CPMenuBarSharedWindow) { [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; @@ -231,7 +231,7 @@ var _CPMenuBarVisible = NO, { if (self === [CPApp mainMenu]) return MENUBAR_HEIGHT; - + return 0.0; } @@ -249,18 +249,18 @@ var _CPMenuBarVisible = NO, - (id)initWithTitle:(CPString)aTitle { self = [super init]; - + if (self) { _title = aTitle; _items = []; - + _autoenablesItems = YES; _showsStateColumn = YES; [self setMinimumWidth:0]; } - + return self; } @@ -287,7 +287,7 @@ var _CPMenuBarVisible = NO, [aMenuItem setMenu:self]; [_items insertObject:aMenuItem atIndex:anIndex]; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidAddItemNotification object:self @@ -306,7 +306,7 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex { var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent]; - + [self insertItem:item atIndex:anIndex]; return item; @@ -351,10 +351,10 @@ var _CPMenuBarVisible = NO, { if (anIndex < 0 || anIndex >= _items.length) return; - + [_items[anIndex] setMenu:nil]; [_items removeObjectAtIndex:anIndex]; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidRemoveItemNotification object:self @@ -369,7 +369,7 @@ var _CPMenuBarVisible = NO, { if ([aMenuItem menu] != self) return; - + [[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidChangeItemNotification object:self @@ -385,10 +385,10 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)itemWithTag:(int)aTag { var index = [self indexOfItemWithTag:aTag]; - + if (index == CPNotFound) return nil; - + return _items[index]; } @@ -400,10 +400,10 @@ var _CPMenuBarVisible = NO, - (CPMenuItem)itemWithTitle:(CPString)aTitle { var index = [self indexOfItemWithTitle:aTitle]; - + if (index == CPNotFound) return nil; - + return _items[index]; } @@ -442,7 +442,7 @@ var _CPMenuBarVisible = NO, { if ([aMenuItem menu] !== self) return CPNotFound; - + return [_items indexOfObjectIdenticalTo:aMenuItem]; } @@ -455,7 +455,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] title] === aTitle) return index; @@ -472,7 +472,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] tag] == aTag) return index; @@ -490,11 +490,11 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) { var item = _items[index]; - + if ([item target] == aTarget && (!anAction || [item action] == anAction)) return index; } @@ -511,7 +511,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([[_items[index] representedObject] isEqual:anObject]) return index; @@ -528,7 +528,7 @@ var _CPMenuBarVisible = NO, { var index = 0, count = _items.length; - + for (; index < count; ++index) if ([_items[index] submenu] == aMenu) return index; @@ -546,7 +546,7 @@ var _CPMenuBarVisible = NO, { [aMenuItem setTarget:aMenuItem]; [aMenuItem setAction:@selector(submenuAction:)]; - + [aMenuItem setSubmenu:aMenu]; } @@ -683,7 +683,7 @@ var _CPMenuBarVisible = NO, itemIndex = [self indexOfItem:anItem]; if (itemIndex === CPNotFound) - throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " + + throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " + anItem + " is not present in menu " + self; } @@ -784,10 +784,10 @@ var _CPMenuBarVisible = NO, + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont { var delegate = [aMenu delegate]; - + if ([delegate respondsToSelector:@selector(menuWillOpen:)]) [delegate menuWillOpen:aMenu]; - + if (!aFont) aFont = [CPFont systemFontOfSize:12.0]; @@ -938,17 +938,7 @@ var _CPMenuBarVisible = NO, var item = _items[index], modifierMask = [item keyEquivalentModifierMask]; - if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString]) - modifierMask |= CPShiftKeyMask; - - if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask)) - { - modifierMask |= CPControlKeyMask; - modifierMask &= ~CPCommandKeyMask; - } - - if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask && - [characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame) + if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]]) { if ([item isEnabled]) [self performActionForItemAtIndex:index]; @@ -956,7 +946,7 @@ var _CPMenuBarVisible = NO, { //beep? } - + return YES; } @@ -975,7 +965,7 @@ var _CPMenuBarVisible = NO, - (void)performActionForItemAtIndex:(unsigned)anIndex { var item = _items[anIndex]; - + [CPApp sendAction:[item action] to:[item target] from:item]; } @@ -1064,7 +1054,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _title = [aCoder decodeObjectForKey:CPMenuTitleKey]; @@ -1076,7 +1066,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey", [self setMinimumWidth:0]; } - + return self; } diff --git a/AppKit/CPMenuItem/CPMenuItem.j b/AppKit/CPMenuItem/CPMenuItem.j index c8d84026e..fb352ed69 100644 --- a/AppKit/CPMenuItem/CPMenuItem.j +++ b/AppKit/CPMenuItem/CPMenuItem.j @@ -29,7 +29,7 @@ @import "CPView.j" @import "_CPMenuItemView.j" -/*! +/*! @ingroup appkit @class CPMenuItem @@ -43,39 +43,39 @@ CPString _title; //CPAttributedString _attributedTitle; - + CPFont _font; - + id _target; SEL _action; - + BOOL _isEnabled; BOOL _isHidden; - + int _tag; int _state; - + CPImage _image; CPImage _alternateImage; CPImage _onStateImage; CPImage _offStateImage; CPImage _mixedStateImage; - + CPMenu _submenu; CPMenu _menu; - + CPString _keyEquivalent; unsigned _keyEquivalentModifierMask; - + int _mnemonicLocation; - + BOOL _isAlternate; int _indentationLevel; - + CPString _toolTip; id _representedObject; CPView _view; - + _CPMenuItemView _menuItemView; } @@ -94,19 +94,19 @@ - (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent { self = [super init]; - + if (self) { _isSeparator = NO; _title = aTitle; _action = anAction; - + _isEnabled = YES; - + _tag = 0; _state = CPOffState; - + _keyEquivalent = aKeyEquivalent || @""; _keyEquivalentModifierMask = CPPlatformActionKeyMask; @@ -114,7 +114,7 @@ _mnemonicLocation = CPNotFound; } - + return self; } @@ -152,7 +152,7 @@ { if (_isHidden == isHidden) return; - + _isHidden = isHidden; [_menu itemChanged:self]; @@ -173,9 +173,9 @@ { if (_isHidden) return YES; - + var supermenu = [_menu supermenu]; - + if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor]) return YES; @@ -228,11 +228,11 @@ if (_title == aTitle) return; - + _title = aTitle; - + [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -260,11 +260,11 @@ { if (_font == aFont) return; - + _font = aFont; [_menu itemChanged:self]; - + [_menuItemView setDirty]; } @@ -316,9 +316,9 @@ CPOffState { if (_state == aState) return; - + _state = aState; - + [_menu itemChanged:self]; [_menuItemView setDirty]; @@ -346,11 +346,11 @@ CPOffState { if (_image == anImage) return; - + _image = anImage; [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -388,7 +388,7 @@ CPOffState { if (_onStateImage == anImage) return; - + _onStateImage = anImage; [_menu itemChanged:self]; } @@ -409,7 +409,7 @@ CPOffState { if (_offStateImage == anImage) return; - + _offStateImage = anImage; [_menu itemChanged:self]; } @@ -430,7 +430,7 @@ CPOffState { if (_mixedStateImage == anImage) return; - + _mixedStateImage = anImage; [_menu itemChanged:self]; } @@ -648,14 +648,14 @@ CPControlKeyMask - (void)setTitleWithMnemonicLocation:(CPString)aTitle { var location = [aTitle rangeOfString:@"&"].location; - + if (location == CPNotFound) [self setTitle:aTitle]; else { [self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]]; [self setMnemonicLocation:location]; - } + } } /*! @@ -696,7 +696,7 @@ CPControlKeyMask { if (aLevel < 0) [CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."]; - + _indentationLevel = MIN(15, aLevel); } @@ -755,11 +755,11 @@ CPControlKeyMask { if (_view === aView) return; - + _view = aView; - + [_menuItemView setDirty]; - + [_menu itemChanged:self]; } @@ -790,7 +790,7 @@ CPControlKeyMask { if (!_menuItemView) _menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self]; - + return _menuItemView; } @@ -844,15 +844,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) { _isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey]; _title = [aCoder decodeObjectForKey:CPMenuItemTitleKey]; - + // _font; - + _target = [aCoder decodeObjectForKey:CPMenuItemTargetKey]; _action = [aCoder decodeObjectForKey:CPMenuItemActionKey]; @@ -887,7 +887,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", _representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil); _view = DEFAULT_VALUE(CPMenuItemViewKey, nil); } - + return self; } @@ -901,11 +901,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", [aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey]; [aCoder encodeObject:_title forKey:CPMenuItemTitleKey]; - + [aCoder encodeObject:_target forKey:CPMenuItemTargetKey]; [aCoder encodeObject:_action forKey:CPMenuItemActionKey]; - ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); + ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO); ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0); @@ -913,7 +913,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey", ENCODE_IFNOT(CPMenuItemImageKey, _image, nil); ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil); - + ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil); ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil); diff --git a/Tests/AppKit/CPMenuTest.j b/Tests/AppKit/CPMenuTest.j new file mode 100644 index 000000000..8b15d0a87 --- /dev/null +++ b/Tests/AppKit/CPMenuTest.j @@ -0,0 +1,182 @@ + +@import +@import +@import +@import + +[CPApplication sharedApplication] + +@implementation CPMenuTest : OJTestCase +{ + CPMenu menu; + BOOL escapeWasCalled; + BOOL escapeNoModifierWasCalled; + BOOL openDocumentWasCalled; + BOOL saveDocumentWasCalled; + BOOL saveDocumentAsWasCalled; + BOOL undoWasCalled; +} + +- (void)setUp +{ + // Set up a fairly complete menu to have something to work with. + menu = [[CPMenu alloc] initWithTitle:@"MainMenu"]; + + var newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"]; + [menu addItem:newMenuItem]; + + var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"]; + [menu addItem:openMenuItem]; + + var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"], + saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil]; + // S + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]]; + // ...vs Shift-S + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:@"S"]]; + + + // Cmd-Escape + [saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Escape the monotonous" action:@selector(escape:) keyEquivalent:CPEscapeFunctionKey]]; + // Escape + var pureEscape = [[CPMenuItem alloc] initWithTitle:@"Escape the cruel" action:@selector(escapeNoModifier:) keyEquivalent:CPEscapeFunctionKey]; + [pureEscape setKeyEquivalentModifierMask:0]; + [saveMenu addItem:pureEscape]; + + [saveMenuItem setSubmenu:saveMenu]; + [menu addItem:saveMenuItem]; + + var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil], + editMenu = [[CPMenu alloc] initWithTitle:@"Edit"], + + undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent], + redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent]; + + [undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask]; + [redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask]; + + [editMenu addItem:undoMenuItem]; + [editMenu addItem:redoMenuItem]; + + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]], + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]], + [editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]]; + + [editMenuItem setSubmenu:editMenu]; + [editMenuItem setHidden:YES]; + + [menu addItem:editMenuItem]; + [menu addItem:[CPMenuItem separatorItem]]; +} + +- (void)_retarget:(CPMenuItem)aMenu +{ + if (!aMenu) + return; + + for(var i=0; i<[aMenu numberOfItems]; i++) + { + var item = [aMenu itemAtIndex:i]; + [item setTarget:self]; + [self _retarget:[item submenu]]; + } +} + +- (void)testKeyEquivalent +{ + [self _retarget:menu]; + + // Don't match anything. + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"b" charactersIgnoringModifiers:"b" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:"o" charactersIgnoringModifiers:"o" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:"o" charactersIgnoringModifiers:"o" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || undoWasCalled]; + [self assertTrue:openDocumentWasCalled message:"expect openDocumentWasCalled"]; + + openDocumentWasCalled = NO; + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:CPUndoKeyEquivalent charactersIgnoringModifiers:CPUndoKeyEquivalent isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled]; + [self assertTrue:undoWasCalled]; +} + +- (void)testKeyEquivalentModifierMask +{ + [self _retarget:menu]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:0 + timestamp:nil windowNumber:nil context:nil + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || openDocumentWasCalled || undoWasCalled]; + [self assertTrue:escapeNoModifierWasCalled]; + + escapeNoModifierWasCalled = NO; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:CPEscapeFunctionKey charactersIgnoringModifiers:CPEscapeFunctionKey isARepeat:NO keyCode:0]]; + [self assertFalse:escapeNoModifierWasCalled || openDocumentWasCalled || undoWasCalled]; + [self assertTrue:escapeWasCalled]; +} + +- (void)testKeyEquivalentWithShiftMask +{ + [self _retarget:menu]; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask + timestamp:nil windowNumber:nil context:nil + characters:@"s" charactersIgnoringModifiers:@"s" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || saveDocumentAsWasCalled || undoWasCalled]; + [self assertTrue:saveDocumentWasCalled message:"saveDocumentWasCalled"]; + + saveDocumentWasCalled = NO; + + [menu performKeyEquivalent:[CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPPlatformActionKeyMask|CPShiftKeyMask + timestamp:nil windowNumber:nil context:nil + characters:@"s" charactersIgnoringModifiers:@"s" isARepeat:NO keyCode:0]]; + [self assertFalse:escapeWasCalled || escapeNoModifierWasCalled || openDocumentWasCalled || saveDocumentWasCalled || undoWasCalled]; + [self assertTrue:saveDocumentAsWasCalled message:"saveDocumentAsWasCalled"]; +} + +- (void)escape:(id)sender +{ + escapeWasCalled = YES; +} + +- (void)escapeNoModifier:(id)sender +{ + escapeNoModifierWasCalled = YES; +} + +- (void)openDocument:(id)sender +{ + openDocumentWasCalled = YES; +} + +- (void)saveDocument:(id)sender +{ + saveDocumentWasCalled = YES; +} + +- (void)saveDocumentAs:(id)sender +{ + saveDocumentAsWasCalled = YES; +} + +- (void)undo:(id)sender +{ + undoWasCalled = YES; +} + +@end From a49b01d396a3680022cf1832f8d6d0eafb814baf Mon Sep 17 00:00:00 2001 From: Thomas Ingham Date: Tue, 8 Jun 2010 22:26:24 -0400 Subject: [PATCH 06/61] Added missing asset. --- .../Themes/Aristo/Resources/HUD/knob-disabled.png | Bin 0 -> 894 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png diff --git a/AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png b/AppKit/Themes/Aristo/Resources/HUD/knob-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6e540414ad3f9bfa1533ce25f7fe5b0ec0112e GIT binary patch literal 894 zcmV-^1A+XBP)82}=^sbKdoHOrt&KdYW z9(G9oAuj>4FA3-Z!dKVV1Ht>i(1%y9EG14%omRuzbXZlAj@z!ej$Ljv>)Rh)zMKcV zK%x7>B_OoAx*9+G`kSvTEj+Q9Nzaf>#7QLLG#Wa!hED09J@Px7g`3~p_+evX;~vl% zE-*Ff;CY96Ap~6{)wg*h96)N>wqx6NSe6ezDx1q;=sL12qiGu1Y!26TkH8(L)n;h4 zgSG&4oAv#MX_|PRH_+;9Yos%C2q8#k<~X|6kyonrp4lc#29 zL+WA5v<0hgtPzbwFfEI{N)0z)i(%*#w)4C69&+Tg2%!D#7uWC1Ken_i%W^CljRN4g z9y`Snqrxx@b_?5k-`%*r3AjP{s122Mz1mElnx8|GLW-gsJLkHtQ?FK?ufO{2m!_`Q z0gK)!j)Zps>eZ^dUC5VH$?3SFs!@dKoxg4u&+~9vEeylp?oOfn<>%|amP@5FU=DXa ze7Gdvs&OC+#9n;q<*t@g00U?OEr!@zPumj%;XBd1OeBgbcNPj{4KZ}lUfy)El^HD|m>WARy-{|4TzswJ> UEpFJp0{{R307*qoM6N<$f?YeabN~PV literal 0 HcmV?d00001 From 478f2d81341116837c7511f3b43fe6104231383e Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Wed, 9 Jun 2010 13:16:45 -0700 Subject: [PATCH 07/61] Name Objective-J allocators to get correct WebKit heap snapshot reports. --- Objective-J/Runtime.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Objective-J/Runtime.js b/Objective-J/Runtime.js index 1df7ab26f..7a88ebb9a 100644 --- a/Objective-J/Runtime.js +++ b/Objective-J/Runtime.js @@ -50,7 +50,7 @@ GLOBAL(objj_method) = function(/*String*/ aName, /*IMP*/ anImplementation, /*Str DISPLAY_NAME(objj_method); -GLOBAL(objj_class) = function() +GLOBAL(objj_class) = function(displayName) { this.isa = NULL; @@ -67,7 +67,14 @@ GLOBAL(objj_class) = function() this.method_store = function() { }; this.method_dtable = this.method_store.prototype; +#if DEBUG + // naming the allocator allows the WebKit heap snapshot tool to display object class names correctly + // HACK: displayName property is not respected so we must eval a function to name it + this.allocator = eval("(function " + (displayName || "OBJJ_OBJECT").replace(/\W/g, "_") + "() { })"); +#else this.allocator = function() { }; +#endif + this._UID = -1; } @@ -325,8 +332,8 @@ var REGISTERED_CLASSES = { }; GLOBAL(objj_allocateClassPair) = function(/*Class*/ superclass, /*String*/ aName) { - var classObject = new objj_class(), - metaClassObject = new objj_class(), + var classObject = new objj_class(aName), + metaClassObject = new objj_class(aName), rootClassObject = classObject; // If we don't have a superclass, we are the root class. From c65e3d4e6d2267866a1c9e2a77e80256c25ef76c Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 9 Jun 2010 14:23:27 -0700 Subject: [PATCH 08/61] Move the bindings test to the manual folder. --- Tests/{AppKit => Manual}/SimpleBindings2/AppController.j | 0 Tests/{AppKit => Manual}/SimpleBindings2/Info.plist | 0 Tests/{AppKit => Manual}/SimpleBindings2/index-debug.html | 0 Tests/{AppKit => Manual}/SimpleBindings2/index.html | 0 Tests/{AppKit => Manual}/SimpleBindings2/main.j | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename Tests/{AppKit => Manual}/SimpleBindings2/AppController.j (100%) rename Tests/{AppKit => Manual}/SimpleBindings2/Info.plist (100%) rename Tests/{AppKit => Manual}/SimpleBindings2/index-debug.html (100%) rename Tests/{AppKit => Manual}/SimpleBindings2/index.html (100%) rename Tests/{AppKit => Manual}/SimpleBindings2/main.j (100%) diff --git a/Tests/AppKit/SimpleBindings2/AppController.j b/Tests/Manual/SimpleBindings2/AppController.j similarity index 100% rename from Tests/AppKit/SimpleBindings2/AppController.j rename to Tests/Manual/SimpleBindings2/AppController.j diff --git a/Tests/AppKit/SimpleBindings2/Info.plist b/Tests/Manual/SimpleBindings2/Info.plist similarity index 100% rename from Tests/AppKit/SimpleBindings2/Info.plist rename to Tests/Manual/SimpleBindings2/Info.plist diff --git a/Tests/AppKit/SimpleBindings2/index-debug.html b/Tests/Manual/SimpleBindings2/index-debug.html similarity index 100% rename from Tests/AppKit/SimpleBindings2/index-debug.html rename to Tests/Manual/SimpleBindings2/index-debug.html diff --git a/Tests/AppKit/SimpleBindings2/index.html b/Tests/Manual/SimpleBindings2/index.html similarity index 100% rename from Tests/AppKit/SimpleBindings2/index.html rename to Tests/Manual/SimpleBindings2/index.html diff --git a/Tests/AppKit/SimpleBindings2/main.j b/Tests/Manual/SimpleBindings2/main.j similarity index 100% rename from Tests/AppKit/SimpleBindings2/main.j rename to Tests/Manual/SimpleBindings2/main.j From 9ab446b7903b0acdc4c96fb0c194c1752aa0aaa2 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 8 Jun 2010 23:22:41 -0400 Subject: [PATCH 09/61] Added image alignment support to CPImageView, CPWindowController always loads a cib from the main bundle for consistency with Cocoa, CPApplication modified to explicitly load the About panel cib from the Framework bundle --- AppKit/CPApplication.j | 4 +- AppKit/CPImageView.j | 101 ++++++++++++++++++++++++++++++++---- AppKit/CPWindowController.j | 4 +- Tools/nib2cib/NSImageView.j | 3 +- 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/AppKit/CPApplication.j b/AppKit/CPApplication.j index 41d8d6dee..7958fc45f 100644 --- a/AppKit/CPApplication.j +++ b/AppKit/CPApplication.j @@ -325,7 +325,9 @@ CPRunContinuesResponse = -1002; applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"], copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"]; - var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"], + var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"], + aboutPanelController = [CPWindowController alloc], + aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController], aboutPanel = [aboutPanelController window], contentView = [aboutPanel contentView], imageView = [contentView viewWithTag:1], diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index 7d365f71f..ab9722cae 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -35,6 +35,16 @@ CPScaleProportionally = 0; CPScaleToFit = 1; CPScaleNone = 2; +CPImageAlignCenter = 0; +CPImageAlignTop = 1; +CPImageAlignTopLeft = 2; +CPImageAlignTopRight = 3; +CPImageAlignLeft = 4; +CPImageAlignBottom = 5; +CPImageAlignBottomLeft = 6; +CPImageAlignBottomRight = 7; +CPImageAlignRight = 8; + var CPImageViewShadowBackgroundColor = nil; var LEFT_SHADOW_INSET = 3.0, @@ -52,14 +62,15 @@ var LEFT_SHADOW_INSET = 3.0, */ @implementation CPImageView : CPControl { - DOMElement _DOMImageElement; + DOMElement _DOMImageElement; - BOOL _hasShadow; - CPView _shadowView; + BOOL _hasShadow; + CPView _shadowView; - BOOL _isEditable; + BOOL _isEditable; - CGRect _imageRect; + CGRect _imageRect; + CPImageAlignment _imageAlignment; } - (id)initWithFrame:(CGRect)aFrame @@ -191,6 +202,30 @@ var LEFT_SHADOW_INSET = 3.0, [self hideOrDisplayContents]; } +/*! + Sets the type of image alignment that should be used to + render the image. + @param anImageAlignment the type of scaling to use +*/ +- (void)setImageAlignment:(CPImageAlignment)anImageAlignment +{ + if (_imageAlignment == anImageAlignment) + return; + + _imageAlignment = anImageAlignment; + + if (![self image]) + return; + + [self setNeedsLayout]; + [self setNeedsDisplay:YES]; +} + +- (unsigned)imageAlignment +{ + return _imageAlignment; +} + /*! Sets the type of image scaling that should be used to render the image. @@ -318,8 +353,49 @@ var LEFT_SHADOW_INSET = 3.0, #endif } - var x = (boundsWidth - width) / 2.0, - y = (boundsHeight - height) / 2.0; + var x, y; + + switch (_imageAlignment) + { + case CPImageAlignLeft: + case CPImageAlignTopLeft: + case CPImageAlignBottomLeft: + x = 0.0; + break; + + case CPImageAlignRight: + case CPImageAlignTopRight: + case CPImageAlignBottomRight: + x = boundsWidth - width; + break; + + case CPImageAlignCenter: + case CPImageAlignTop: + case CPImageAlignBottom: + x = (boundsWidth - width) / 2.0; + break; + } + + switch (_imageAlignment) + { + case CPImageAlignTop: + case CPImageAlignTopLeft: + case CPImageAlignTopRight: + y = 0.0; + break; + + case CPImageAlignBottom: + case CPImageAlignBottomLeft: + case CPImageAlignBottomRight: + y = boundsHeight - height; + break; + + case CPImageAlignLeft: + case CPImageAlignRight: + case CPImageAlignCenter: + y = (boundsHeight - height) / 2.0; + break; + } #if PLATFORM(DOM) CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y); @@ -380,10 +456,11 @@ var LEFT_SHADOW_INSET = 3.0, @end -var CPImageViewImageKey = @"CPImageViewImageKey", - CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", - CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", - CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; +var CPImageViewImageKey = @"CPImageViewImageKey", + CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", + CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey", + CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", + CPImageViewIsEditableKey = @"CPImageViewIsEditableKey"; @implementation CPImageView (CPCoding) @@ -416,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", #endif [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]]; + [self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]]; if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO) [self setEditable:YES]; @@ -450,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey", _subviews = actualSubviews; [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey]; + [aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey]; if (_isEditable) [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey]; diff --git a/AppKit/CPWindowController.j b/AppKit/CPWindowController.j index aebbc5e89..2d011af98 100644 --- a/AppKit/CPWindowController.j +++ b/AppKit/CPWindowController.j @@ -133,7 +133,7 @@ if (_window) return; - [[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]]; + [[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]]; } /*! @@ -424,7 +424,7 @@ if (_windowCibPath) return _windowCibPath; - return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"]; + return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"]; } // Setting and Getting Window Attributes diff --git a/Tools/nib2cib/NSImageView.j b/Tools/nib2cib/NSImageView.j index 2624c2582..9c83e4a7b 100644 --- a/Tools/nib2cib/NSImageView.j +++ b/Tools/nib2cib/NSImageView.j @@ -34,6 +34,7 @@ var cell = [aCoder decodeObjectForKey:@"NSCell"]; [self setImageScaling:[cell imageScaling]]; + [self setImageAlignment:[cell imageAlignment]]; _isEditable = [cell isEditable]; } @@ -92,7 +93,7 @@ NSImageScalingToCPImageScaling[NSImageScaleProportionallyUpOrDown] = CPScalePro @implementation NSImageCell : NSCell { BOOL _animates @accessors; - NSImageAlignment _imageAlignment @accessors; + NSImageAlignment _imageAlignment @accessors(readonly, getter=imageAlignment); NSImageScaling _imageScaling @accessors(readonly, getter=imageScaling); NSImageFrameStyle _frameStyle @accessors; } From 421ae6b3162ec05da3d9c4b9d687367764f213d8 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 10 Jun 2010 10:41:15 -0700 Subject: [PATCH 10/61] Make CPButton archive its key equivalents, and make nib2cib support the feature. --- AppKit/CPButton.j | 14 +++++++++++++- Objective-J/CFPropertyList.js | 12 +++++++++--- Tools/nib2cib/Converter.j | 6 +++--- Tools/nib2cib/NSButton.j | 9 +++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index b8997986c..744de7a29 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -629,7 +629,9 @@ var CPButtonImageKey = @"CPButtonImageKey", CPButtonTitleKey = @"CPButtonTitleKey", CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey", CPButtonIsBorderedKey = @"CPButtonIsBorderedKey", - CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey"; + CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey", + CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey", + CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey"; @implementation CPButton (CPCoding) @@ -653,6 +655,11 @@ var CPButtonImageKey = @"CPButtonImageKey", [self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]]; + if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey]) + [self setKeyEquivalent:CFData.decodeBase64ToString([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; + + [self setKeyEquivalentModifierMask:[aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey]]; + [self setNeedsLayout]; [self setNeedsDisplay:YES]; } @@ -675,6 +682,11 @@ var CPButtonImageKey = @"CPButtonImageKey", [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey]; [aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey]; + + if (_keyEquivalent) + [aCoder encodeObject:CFData.encodeBase64String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; + + [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey]; } @end diff --git a/Objective-J/CFPropertyList.js b/Objective-J/CFPropertyList.js index 39ba97e13..5faeb473b 100644 --- a/Objective-J/CFPropertyList.js +++ b/Objective-J/CFPropertyList.js @@ -306,6 +306,8 @@ var XML_XML = "xml", #define PARENT_NODE(anXMLNode) (anXMLNode.parentNode) #define DOCUMENT_ELEMENT(aDocument) (aDocument.documentElement) +#define HAS_ATTRIBUTE_VALUE(anXMLNode, anAttributeName, aValue) (anXMLNode.getAttribute(anAttributeName) === aValue) + #define IS_OF_TYPE(anXMLNode, aType) (NODE_NAME(anXMLNode) === aType) #define IS_PLIST(anXMLNode) IS_OF_TYPE(anXMLNode, PLIST_PLIST) @@ -559,13 +561,17 @@ CFPropertyList.propertyListFromXML = function(/*String | XMLNode*/ aStringOrXMLN case PLIST_DICTIONARY: object = new CFMutableDictionary(); containers.push(object); break; - + case PLIST_NUMBER_REAL: object = parseFloat(CHILD_VALUE(XMLNode)); break; case PLIST_NUMBER_INTEGER: object = parseInt(CHILD_VALUE(XMLNode), 10); break; - - case PLIST_STRING: object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + + case PLIST_STRING: if (HAS_ATTRIBUTE_VALUE(XMLNode, "type", "base64")) + object = FIRST_CHILD(XMLNode) ? CFData.decodeBase64ToString(CHILD_VALUE(XMLNode)) : ""; + else + object = decodeHTMLComponent(FIRST_CHILD(XMLNode) ? CHILD_VALUE(XMLNode) : ""); + break; case PLIST_BOOLEAN_TRUE: object = YES; diff --git a/Tools/nib2cib/Converter.j b/Tools/nib2cib/Converter.j index 46eb0036a..88175bb48 100644 --- a/Tools/nib2cib/Converter.j +++ b/Tools/nib2cib/Converter.j @@ -121,9 +121,9 @@ ConverterConversionException = @"ConverterConversionException"; else plistContents = plistContents.replace(/\\s*CF\$UID\s*\<\/key\>/g, "CP$UID"); - plistContents = plistContents.replace(/\u001b/g, function(c) { - CPLog.warn("Warning: Stripping character 0x"+c.charCodeAt(0).toString(16)); - return ""; + plistContents = plistContents.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]<\/string>/g, function(c) { + CPLog.warn("Warning: Converting character 0x"+c.charCodeAt(8).toString(16)+" to base64 representation"); + return ""+CFData.encodeBase64String(c.charAt(8))+""; }); return [CPData dataWithRawString:plistContents]; diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 9c13724e4..130e4f395 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -180,6 +180,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; } } + [self setKeyEquivalent:[cell keyEquivalent]]; + [self setKeyEquivalentModifierMask:[cell keyEquivalentModifierMask]]; + return [self NS_initWithCoder:aCoder]; } @@ -203,6 +206,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; CPString _title @accessors(readonly, getter=title); CPImage _alternateImage @accessors(readonly, getter=alternateImage); + + CPString _keyEquivalent @accessors(readonly, getter=keyEquivalent); + unsigned _keyEquivalentModifierMask @accessors(readonly, getter=keyEquivalentModifierMask); } - (id)initWithCoder:(CPCoder)aCoder @@ -223,6 +229,9 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _objectValue = [self state]; _alternateImage = [aCoder decodeObjectForKey:@"NSAlternateImage"]; + + _keyEquivalent = [aCoder decodeObjectForKey:@"NSKeyEquivalent"]; + _keyEquivalentModifierMask = buttonFlags2 >> 8; } return self; From 51825db71699ae12de534f48b6194c85bc170235 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 14 Feb 2010 22:52:47 -0300 Subject: [PATCH 11/61] Fixed: [CPDate description] did not generate a correct date for users in timezones with a negative timezone offset. --- Foundation/CPDate.j | 5 +++-- Tests/Foundation/CPDateTest.j | 37 ++++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Foundation/CPDate.j b/Foundation/CPDate.j index 6340ef48c..cba9ec382 100644 --- a/Foundation/CPDate.j +++ b/Foundation/CPDate.j @@ -177,10 +177,11 @@ var CPDateReferenceDate = new Date(Date.UTC(2001, 1, 1, 0, 0, 0, 0)); */ - (CPString)description { - var hours = Math.floor(self.getTimezoneOffset() / 60), + var positive = self.getTimezoneOffset() >= 0, + hours = FLOOR(self.getTimezoneOffset() / 60), minutes = self.getTimezoneOffset() - hours * 60; - return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d +%02d%02d", self.getFullYear(), self.getMonth() + 1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), hours, minutes]; + return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d %s%02d%02d", self.getFullYear(), self.getMonth()+1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), positive ? "+" : "-", ABS(hours), ABS(minutes)]; } - (id)copy diff --git a/Tests/Foundation/CPDateTest.j b/Tests/Foundation/CPDateTest.j index 4668d37af..62d9600b2 100644 --- a/Tests/Foundation/CPDateTest.j +++ b/Tests/Foundation/CPDateTest.j @@ -62,15 +62,46 @@ - (void)testDescription { - // Unfortunately the result will be different depending on the testing machine's timezone. + // Unfortunately the result will be different depending on the testing machine's timezone, so + // this test turns out to be more complex than the code tested. We can't just reuse the + // original code as then we'd have exactly the same bugs. var date = [CPDate dateWithTimeIntervalSince1970: 1234567890], + expectedDay = 13, expectedHour = 23, expectedMinute = 31, + offsetPositive = date.getTimezoneOffset() >= 0, offsetHours = Math.floor(date.getTimezoneOffset() / 60), offsetMinutes = date.getTimezoneOffset() - offsetHours * 60, - expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes]; + expectedString; + expectedHour -= offsetHours; + expectedMinute -= offsetMinutes; + if (expectedMinute < 0) + { + expectedMinute += 60; + expectedHour--; + } + else if (expectedMinute > 59) + { + expectedMinute -= 60; + expectedHour++; + } + if (expectedHour < 0) + { + expectedHour += 24; + expectedDay--; + } + else if (expectedHour > 23) + { + expectedHour -= 24; + expectedDay++; + } - [self assert:expectedString equals:[date description]]; + if (offsetPositive) + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 +%02d%02d", expectedDay, expectedHour, expectedMinute, offsetHours, offsetMinutes]; + else + expectedString = [CPString stringWithFormat:"2009-02-%02d %02d:%02d:30 -%02d%02d", expectedDay, expectedHour, expectedMinute, ABS(offsetHours), ABS(offsetMinutes)]; + + [self assert:expectedString equals: [date description]]; } - (void)testCopy From 17669fd09d13efe1cc097bd04eda48b7a07e0f9a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 17:24:13 -0400 Subject: [PATCH 12/61] Optimized _triggersKeyEquivalent for a 6.5% performance gain in the CPKeyEquivalentPerformance test. --- AppKit/CPEvent.j | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index 0fca38549..cf62a7597 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -178,7 +178,8 @@ CPDOMEventTouchEnd = "touchend"; CPDOMEventTouchCancel = "touchcancel"; var _CPEventPeriodicEventPeriod = 0, - _CPEventPeriodicEventTimer = nil; + _CPEventPeriodicEventTimer = nil, + _CPEventUpperCaseRegex = new RegExp("[A-Z]"); /*! @ingroup appkit @@ -521,10 +522,7 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask { - var characters = [self charactersIgnoringModifiers], - modifierFlags = [self modifierFlags]; - - if (new RegExp("[A-Z]").test(aKeyEquivalent)) + if (_CPEventUpperCaseRegex.test(aKeyEquivalent)) aKeyEquivalentModifierMask |= CPShiftKeyMask; if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask)) @@ -533,10 +531,10 @@ var _CPEventPeriodicEventPeriod = 0, aKeyEquivalentModifierMask &= ~CPCommandKeyMask; } - if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) + if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) return NO; - return [characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; + return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; } - (BOOL)_couldBeKeyEquivalent From 5ed475eeddc3de4cf473586c6e4479f88e053d28 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 9 Jun 2010 14:15:27 -0400 Subject: [PATCH 13/61] Slightly faster _couldBeKeyEquivalent (1% of runtime in 3000 calls). Performance test included. --- AppKit/CPEvent.j | 27 ++++---- Tests/AppKit/CPKeyEquivalentPerformance.j | 76 +++++++++++++++++++++++ 2 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 Tests/AppKit/CPKeyEquivalentPerformance.j diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index cf62a7597..b2b62fa00 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -21,6 +21,7 @@ */ @import +@import "CPText.j" #include "CoreGraphics/CGGeometry.h" @@ -539,22 +540,20 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_couldBeKeyEquivalent { - // FIXME: More cases? Space? - return _type === CPKeyDown && - ((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) && - [_characters length] > 0) || - [self _hasActionCharacter]); -} + if (_type !== CPKeyDown) + return NO; -- (BOOL)_hasActionCharacter -{ - var characters = [self characters], - characterCount = [characters length]; + var characterCount = _characters.length; + + if (!characterCount) + return NO; + + if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) + return YES; for(var i=0; i +@import +@import +@import + +[CPApplication sharedApplication]; + +@implementation CPKeyEquivalentPerformance : OJTestCase + +- (void)testKeyEquivalentSpeed +{ + var REPEATS = 1000, + theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0,0,200,150) + styleMask:CPWindowNotSizable], + contentView = [theWindow contentView], + subView1 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + subView2 = [[CPView alloc] initWithFrame:CGRectMakeZero()], + button1 = [CPButton buttonWithTitle:"when"], + button2 = [CPButton buttonWithTitle:"you have eliminated"], + button3 = [CPButton buttonWithTitle:"the impossible"]; + + [contentView addSubview:subView1]; + [contentView addSubview:subView2]; + [subView1 addSubview:button1]; + [subView2 addSubview:button2]; + [subView2 addSubview:button3]; + + [button1 setTarget:self]; + [button1 setAction:@selector(clicked:)]; + [button1 setKeyEquivalent:"a"]; + [button1 setKeyEquivalentModifierMask:CPControlKeyMask]; + button1.clicks = 0; + + [button2 setTarget:self]; + [button2 setAction:@selector(clicked:)]; + [button2 setKeyEquivalent:"a"]; + [button2 setKeyEquivalentModifierMask:CPAlternateKeyMask|CPCommandKeyMask]; + button2.clicks = 0; + + [button3 setTarget:self]; + [button3 setAction:@selector(clicked:)]; + [button3 setKeyEquivalent:"A"]; + [button3 setKeyEquivalentModifierMask:CPControlKeyMask]; + button3.clicks = 0; + + var start = (new Date).getTime(); + + for (var i=0; i Date: Thu, 10 Jun 2010 13:29:47 -0700 Subject: [PATCH 14/61] Slight switch statement change so that nil/0 are treated equivalently. --- AppKit/CPImageView.j | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/AppKit/CPImageView.j b/AppKit/CPImageView.j index ab9722cae..017b59ad3 100644 --- a/AppKit/CPImageView.j +++ b/AppKit/CPImageView.j @@ -368,10 +368,8 @@ var LEFT_SHADOW_INSET = 3.0, case CPImageAlignBottomRight: x = boundsWidth - width; break; - - case CPImageAlignCenter: - case CPImageAlignTop: - case CPImageAlignBottom: + + default: x = (boundsWidth - width) / 2.0; break; } @@ -389,10 +387,8 @@ var LEFT_SHADOW_INSET = 3.0, case CPImageAlignBottomRight: y = boundsHeight - height; break; - - case CPImageAlignLeft: - case CPImageAlignRight: - case CPImageAlignCenter: + + default: y = (boundsHeight - height) / 2.0; break; } From 443e23e348e578db3133f9b653fc538ec6a437bc Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 9 Jun 2010 19:28:42 -0700 Subject: [PATCH 15/61] Without the commas, these create global variables --- AppKit/CPViewAnimation.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AppKit/CPViewAnimation.j b/AppKit/CPViewAnimation.j index b1bc4d414..594b638a2 100644 --- a/AppKit/CPViewAnimation.j +++ b/AppKit/CPViewAnimation.j @@ -79,9 +79,9 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut"; while (animationIndex--) { var dictionary = [_viewAnimations objectAtIndex:animationIndex], - view = [self _targetView:dictionary] - startFrame = [self _startFrame:dictionary] - endFrame = [self _endFrame:dictionary] + view = [self _targetView:dictionary], + startFrame = [self _startFrame:dictionary], + endFrame = [self _endFrame:dictionary], differenceFrame = _CGRectMakeZero(); differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; From 1899250a530115543729ce59f6eabb44a0a10b13 Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Wed, 9 Jun 2010 19:29:04 -0700 Subject: [PATCH 16/61] Semicolons are nice... --- AppKit/CPCollectionView.j | 2 +- AppKit/CPColor.j | 2 +- AppKit/CPCursor.j | 2 +- AppKit/CPKeyValueBinding.j | 2 +- AppKit/CPMenu/_CPMenuManager.j | 2 +- AppKit/CPMenuItem/_CPMenuItemStandardView.j | 2 +- AppKit/CPMenuItem/_CPMenuItemView.j | 2 +- AppKit/CPSplitView.j | 2 +- AppKit/CPTableView.j | 6 +++--- AppKit/CPView.j | 2 +- AppKit/CPWindow/CPWindow.j | 6 +++--- AppKit/Cib/CPCib.j | 2 +- CommonJS/lib/cappuccino/cib-analysis-tools.j | 4 ++-- Foundation/CPArray.j | 2 +- Foundation/CPKeyValueObserving.j | 6 +++--- Foundation/CPObject.j | 2 +- Foundation/CPTimer.j | 2 +- 17 files changed, 24 insertions(+), 24 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 11d4b2ed6..80957124c 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -313,7 +313,7 @@ [_items[index] setSelected:YES]; if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) - [_delegate collectionViewDidChangeSelection:self] + [_delegate collectionViewDidChangeSelection:self]; } /*! diff --git a/AppKit/CPColor.j b/AppKit/CPColor.j index b6eda360c..3203257bf 100644 --- a/AppKit/CPColor.j +++ b/AppKit/CPColor.j @@ -422,7 +422,7 @@ var cachedBlackColor, parseInt(parts[1], 10) / 255.0, parseInt(parts[2], 10) / 255.0, parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0 - ] + ]; _cssString = aString; diff --git a/AppKit/CPCursor.j b/AppKit/CPCursor.j index 45b3f1ab8..d550fb10c 100755 --- a/AppKit/CPCursor.j +++ b/AppKit/CPCursor.j @@ -197,7 +197,7 @@ var currentCursor = nil, + (void)unhide { - [self _setCursorCSS:[currentCursor _cssString]] + [self _setCursorCSS:[currentCursor _cssString]]; } + (void)setHiddenUntilMouseMoves:(BOOL)flag diff --git a/AppKit/CPKeyValueBinding.j b/AppKit/CPKeyValueBinding.j index 09ae8a59e..3aabc98a6 100644 --- a/AppKit/CPKeyValueBinding.j +++ b/AppKit/CPKeyValueBinding.j @@ -108,7 +108,7 @@ var CPBindingOperationAnd = 0, count = allKeys.length; while (count--) - [anObject unbind:[bindings objectForKey:allKeys[count]]] + [anObject unbind:[bindings objectForKey:allKeys[count]]]; [bindingsMap removeObjectForKey:[anObject hash]]; } diff --git a/AppKit/CPMenu/_CPMenuManager.j b/AppKit/CPMenu/_CPMenuManager.j index e022f8ddc..18d1021e1 100644 --- a/AppKit/CPMenu/_CPMenuManager.j +++ b/AppKit/CPMenu/_CPMenuManager.j @@ -96,7 +96,7 @@ var SharedMenuManager = nil; // Close Menu Event. if (type === CPAppKitDefined) - return [self completeTracking] + return [self completeTracking]; [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES]; diff --git a/AppKit/CPMenuItem/_CPMenuItemStandardView.j b/AppKit/CPMenuItem/_CPMenuItemStandardView.j index db15e5417..63777e96f 100644 --- a/AppKit/CPMenuItem/_CPMenuItemStandardView.j +++ b/AppKit/CPMenuItem/_CPMenuItemStandardView.j @@ -39,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil, SUBMENU_INDICATOR_COLOR = [CPColor grayColor]; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPMenuItem/_CPMenuItemView.j b/AppKit/CPMenuItem/_CPMenuItemView.j index d4ef798f0..7b5438a17 100644 --- a/AppKit/CPMenuItem/_CPMenuItemView.j +++ b/AppKit/CPMenuItem/_CPMenuItemView.j @@ -43,7 +43,7 @@ var _CPMenuItemSelectionColor = nil, return; _CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; - _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0] + _CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]; var bundle = [CPBundle bundleForClass:self]; diff --git a/AppKit/CPSplitView.j b/AppKit/CPSplitView.j index 70f1a9282..4a90dcf99 100644 --- a/AppKit/CPSplitView.j +++ b/AppKit/CPSplitView.j @@ -152,7 +152,7 @@ var CPSplitViewHorizontalImage = nil, _isPaneSplitter = shouldBePaneSplitter; if(_DOMDividerElements[_drawingDivider]) - [self _setupDOMDivider] + [self _setupDOMDivider]; // The divider changes size when pane splitter mode is toggled, so the // subviews need to change size too. diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index c8bac1aae..3a2b0f0d9 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -654,9 +654,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; return; _sourceListActiveGradient = [aDictionary valueForKey:CPSourceListGradient]; - _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor] + _sourceListActiveTopLineColor = [aDictionary valueForKey:CPSourceListTopLineColor]; _sourceListActiveBottomLineColor = [aDictionary valueForKey:CPSourceListBottomLineColor]; - [self setNeedsDisplay:YES] + [self setNeedsDisplay:YES]; } /*! @@ -3481,7 +3481,7 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey", _gridColor = [aCoder decodeObjectForKey:CPTableViewGridColorKey] || [CPColor grayColor]; _gridStyleMask = [aCoder decodeIntForKey:CPTableViewGridStyleMaskKey] || CPTableViewGridNone; - _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey] + _usesAlternatingRowBackgroundColors = [aCoder decodeObjectForKey:CPTableViewUsesAlternatingBackgroundKey]; _alternatingRowBackgroundColors = [[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]]; diff --git a/AppKit/CPView.j b/AppKit/CPView.j index 3085a06fe..56025cd47 100644 --- a/AppKit/CPView.j +++ b/AppKit/CPView.j @@ -1679,7 +1679,7 @@ setBoundsOrigin: var theWindow = [self window]; [theWindow _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [theWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 00cd3b8de..caf713d63 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1600,7 +1600,7 @@ CPTexturedBackgroundWindowMask if (!pasteboardTypes) return; - [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes] + [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]; if ([_inclusiveRegisteredDraggedTypes count] === 0) _inclusiveRegisteredDraggedTypes = nil; @@ -1631,7 +1631,7 @@ CPTexturedBackgroundWindowMask return; [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; - [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes] + [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; _registeredDraggedTypesArray = nil; @@ -1644,7 +1644,7 @@ CPTexturedBackgroundWindowMask - (CPArray)registeredDraggedTypes { if (!_registeredDraggedTypesArray) - _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects] + _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; return _registeredDraggedTypesArray; } diff --git a/AppKit/Cib/CPCib.j b/AppKit/Cib/CPCib.j index f9a3eeafc..5cc8e4fd2 100644 --- a/AppKit/Cib/CPCib.j +++ b/AppKit/Cib/CPCib.j @@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects]; - [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; diff --git a/CommonJS/lib/cappuccino/cib-analysis-tools.j b/CommonJS/lib/cappuccino/cib-analysis-tools.j index cab6a919a..2427987f8 100644 --- a/CommonJS/lib/cappuccino/cib-analysis-tools.j +++ b/CommonJS/lib/cappuccino/cib-analysis-tools.j @@ -17,7 +17,7 @@ function findCibClassDependencies(cibPath) { } // make sure CPApp is init'd - [CPApplication sharedApplication] + [CPApplication sharedApplication]; try { var x = [cib pressInstantiate]; @@ -61,7 +61,7 @@ function findCibClassDependencies(cibPath) { var topLevelObjects = nil;//[anExternalNameTable objectForKey:CPCibTopLevelObjects]; - [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects] + [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; // [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index 70d33f9db..27acbd1f2 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -796,7 +796,7 @@ */ - (CPArray)sortedArrayUsingSelector:(SEL)aSelector { - var sorted = [self copy] + var sorted = [self copy]; [sorted sortUsingSelector:aSelector]; diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 66d08fbb0..12f2f6e51 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -738,7 +738,7 @@ var _kvoInsertMethodForMethod = function _kvoInsertMethodForMethod(theKey, theMe { [self willChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, object, index); - [self didChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeInsertion valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } @@ -748,7 +748,7 @@ var _kvoReplaceMethodForMethod = function _kvoReplaceMethodForMethod(theKey, the { [self willChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, index, object); - [self didChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeReplacement valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } @@ -758,7 +758,7 @@ var _kvoRemoveMethodForMethod = function _kvoRemoveMethodForMethod(theKey, theMe { [self willChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; theMethod.method_imp(self, _cmd, index); - [self didChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey] + [self didChange:CPKeyValueChangeRemoval valuesAtIndexes:[CPIndexSet indexSetWithIndex:index] forKey:theKey]; } } diff --git a/Foundation/CPObject.j b/Foundation/CPObject.j index c518f4f70..34d023421 100644 --- a/Foundation/CPObject.j +++ b/Foundation/CPObject.j @@ -548,7 +548,7 @@ CPLog(@"Got some class: %@", inst); objj_class.prototype.toString = objj_object.prototype.toString = function() { if (this.isa && class_getInstanceMethod(this.isa, "description") != NULL) - return [this description] + return [this description]; else return String(this) + " (-description not implemented)"; } diff --git a/Foundation/CPTimer.j b/Foundation/CPTimer.j index 6e14ba46a..5c25f1c59 100644 --- a/Foundation/CPTimer.j +++ b/Foundation/CPTimer.j @@ -62,7 +62,7 @@ */ + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat { - var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat] + var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat]; //add to the runloop [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode]; From 1edb0bcc4a8204d1d08773ed279bfb47b2b654ce Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Thu, 10 Jun 2010 16:13:48 -0700 Subject: [PATCH 17/61] Fix for null key equivalents. --- AppKit/CPEvent.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index b2b62fa00..f50c15130 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -523,6 +523,9 @@ var _CPEventPeriodicEventPeriod = 0, - (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask { + if (!aKeyEquivalent) + return NO; + if (_CPEventUpperCaseRegex.test(aKeyEquivalent)) aKeyEquivalentModifierMask |= CPShiftKeyMask; From 9ff056f07338c5b2ad2d7c0e1cbd88355c18b231 Mon Sep 17 00:00:00 2001 From: Derek Hammer Date: Thu, 10 Jun 2010 17:03:43 -0500 Subject: [PATCH 18/61] Making the DisclosureButton a little more subtle. Adding shadow to the disclosure buttons. --- AppKit/CPOutlineView.j | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/AppKit/CPOutlineView.j b/AppKit/CPOutlineView.j index 06812521a..f3bb21bac 100644 --- a/AppKit/CPOutlineView.j +++ b/AppKit/CPOutlineView.j @@ -1245,13 +1245,34 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt CGContextAddLineToPoint(context, 9.0, 0.0); CGContextAddLineToPoint(context, 4.5, 8.0); CGContextAddLineToPoint(context, 0.0, 0.0); - + CGContextClosePath(context); - var isHighlighted = [self hasThemeState:CPThemeStateHighlighted]; - var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]); - - CGContextSetFillColor(context, color); + CGContextSetFillColor(context, + colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected], + [self hasThemeState:CPThemeStateHighlighted])); CGContextFillPath(context); + + + CGContextBeginPath(context); + CGContextMoveToPoint(context, 0.0, 0.0); + if(_angle === 0.0) { + CGContextAddLineToPoint(context, 4.5, 8.0); + CGContextAddLineToPoint(context, 9.0, 0.0); + } else { + CGContextAddLineToPoint(context, 4.5, 8.0); + } + CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]); + CGContextStrokePath(context); } @end + +var colorForDisclosureTriangle = function(isSelected, isHighlighted) { + return isSelected + ? (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0]) + : (isHighlighted + ? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0] + : [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]); +} From f62d81e79f855728de286440dbd57e3038e5a411 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Thu, 10 Jun 2010 22:37:52 -0500 Subject: [PATCH 19/61] Fix for nib2cib breaking with an emptry class implementation. --- AppKit/CPText.j | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/AppKit/CPText.j b/AppKit/CPText.j index 1ef33efe1..5458583ec 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -31,10 +31,9 @@ CPBackspaceCharacter = "\u0008"; CPBackTabCharacter = "\u0019"; CPDeleteCharacter = "\u007f"; -@implementation CPText : CPView +/*@implementation CPText : CPView { } -@end - +@end*/ From dcec14decdee22afb2219ba0b83466c4c72185e1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 20:49:43 -0400 Subject: [PATCH 20/61] Fixed: delete (backspace) and forward delete were switched as compared to Cocoa. Fixed: delete could not be used as a key equivalent without a modifier. --- AppKit/CPEvent.j | 1 + AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index f50c15130..581c3349a 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -560,6 +560,7 @@ var _CPEventPeriodicEventPeriod = 0, { case CPBackspaceCharacter: case CPDeleteCharacter: + case CPDeleteFunctionKey: case CPTabCharacter: case CPCarriageReturnCharacter: case CPEscapeFunctionKey: diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index e5bd7a19d..2132d0c80 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -144,8 +144,8 @@ var KeyCodesToPrevent = {}, KeyCodesToPrevent[CPKeyCodes.A] = YES; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPBackspaceCharacter; -KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter; +KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter; KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter; KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey; From 44555ac72405e2b8446be25f804f5950e9f99e7f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 20:38:41 -0400 Subject: [PATCH 21/61] UTF compatible CFData base64 string encoder and decoder. Use it for CPButton key equivalent archiving. Also ordered CPText.j constants by value and removed the empty CPText class definition as it caused errors with nib2cib. Fixed: the key equivalent for forward delete (CPDeleteFunctionKey, \uF728) was transformed to '(' (\u0028) when archived and unarchived. --- AppKit/CPButton.j | 4 ++-- AppKit/CPText.j | 15 ++++----------- Objective-J/CFData.js | 30 ++++++++++++++++++++++++++++++ Tests/Objective-J/base64Test.j | 8 +++++++- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 744de7a29..75206a02c 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -656,7 +656,7 @@ var CPButtonImageKey = @"CPButtonImageKey", [self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]]; if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey]) - [self setKeyEquivalent:CFData.decodeBase64ToString([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; + [self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])]; [self setKeyEquivalentModifierMask:[aCoder decodeObjectForKey:CPButtonKeyEquivalentMaskKey]]; @@ -684,7 +684,7 @@ var CPButtonImageKey = @"CPButtonImageKey", [aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey]; if (_keyEquivalent) - [aCoder encodeObject:CFData.encodeBase64String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; + [aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey]; [aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey]; } diff --git a/AppKit/CPText.j b/AppKit/CPText.j index 5458583ec..4ac6354d4 100644 --- a/AppKit/CPText.j +++ b/AppKit/CPText.j @@ -22,18 +22,11 @@ @import "CPView.j" -CPTabCharacter = "\u0009"; -CPFormFeedCharacter = "\u000c"; -CPNewlineCharacter = "\u000a"; -CPCarriageReturnCharacter = "\u000d"; CPEnterCharacter = "\u0003"; CPBackspaceCharacter = "\u0008"; +CPTabCharacter = "\u0009"; +CPNewlineCharacter = "\u000a"; +CPFormFeedCharacter = "\u000c"; +CPCarriageReturnCharacter = "\u000d"; CPBackTabCharacter = "\u0019"; CPDeleteCharacter = "\u007f"; - -/*@implementation CPText : CPView -{ - -} - -@end*/ diff --git a/Objective-J/CFData.js b/Objective-J/CFData.js index 51743a5a9..7898756f7 100644 --- a/Objective-J/CFData.js +++ b/Objective-J/CFData.js @@ -227,6 +227,11 @@ CFData.decodeBase64ToString = function(input, strip) return CFData.bytesToString(CFData.decodeBase64ToArray(input, strip)); } +CFData.decodeBase64ToUtf16String = function(input, strip) +{ + return CFData.bytesToUtf16String(CFData.decodeBase64ToArray(input, strip)); +} + CFData.bytesToString = function(bytes) { // This is relatively efficient, I think: @@ -242,3 +247,28 @@ CFData.encodeBase64String = function(input) return CFData.encodeBase64Array(temp); } + +CFData.bytesToUtf16String = function(bytes) +{ + // Strings are encoded with 16 bits per character. + var temp = []; + for (var i = 0; i < bytes.length; i+=2) + temp.push(bytes[i+1] << 8 | bytes[i]); + // This is relatively efficient, I think: + return String.fromCharCode.apply(NULL, temp); +} + + +CFData.encodeBase64Utf16String = function(input) +{ + // charCodeAt returns UTF-16. + var temp = []; + for (var i = 0; i < input.length; i++) + { + var c = input.charCodeAt(i); + temp.push(input.charCodeAt(i) & 0xFF); + temp.push((input.charCodeAt(i) & 0xFF00) >> 8); + } + + return CFData.encodeBase64Array(temp); +} diff --git a/Tests/Objective-J/base64Test.j b/Tests/Objective-J/base64Test.j index 43186ff9b..bce099d2c 100644 --- a/Tests/Objective-J/base64Test.j +++ b/Tests/Objective-J/base64Test.j @@ -42,10 +42,16 @@ var base64TestStrings = [ { var result = CFData.decodeBase64ToArray(base64TestStrings[i][1]), expected = base64TestStrings[i][0]; - + for (var j = 0; j < expected.length || j < result.length; j++) [self assert:result[j] equals:expected.charCodeAt(j)]; } } +- (void)test_CFData_encodeUtfString +{ + var utfTest = "\uF728"; // A common key equivalent. + [self assert:CFData.decodeBase64ToUtf16String(CFData.encodeBase64Utf16String(utfTest)) equals:utfTest]; +} + @end From 854481e395bdcf39285ef683f5da8d0d6d375ad9 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 13:03:07 -0400 Subject: [PATCH 22/61] Fixes #710. Treat \r and \n key equivalents as the same key (return). --- AppKit/CPEvent.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AppKit/CPEvent.j b/AppKit/CPEvent.j index 581c3349a..6c05c96d6 100644 --- a/AppKit/CPEvent.j +++ b/AppKit/CPEvent.j @@ -538,6 +538,10 @@ var _CPEventPeriodicEventPeriod = 0, if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask) return NO; + // Treat \r and \n as the same key equivalent. See issue #710. + if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter) + return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent; + return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame; } @@ -563,6 +567,7 @@ var _CPEventPeriodicEventPeriod = 0, case CPDeleteFunctionKey: case CPTabCharacter: case CPCarriageReturnCharacter: + case CPNewlineCharacter: case CPEscapeFunctionKey: case CPPageUpFunctionKey: case CPPageDownFunctionKey: From c28222e04daeda132e38e0677f11009fa25662d4 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 11 Jun 2010 12:38:25 -0400 Subject: [PATCH 23/61] Test CPResponder's interpretKeyEvents in preparation for rewrite. --- Tests/AppKit/CPResponderTest.j | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 Tests/AppKit/CPResponderTest.j diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j new file mode 100644 index 000000000..891d3076b --- /dev/null +++ b/Tests/AppKit/CPResponderTest.j @@ -0,0 +1,71 @@ +@import +@import +@import + +@import + +[CPApplication sharedApplication] + +@implementation CPResponderTest : OJTestCase +{ + CPWindow theWindow; + CPResponder responder; +} + +- (void)setUp +{ + responder = [TestResponder new]; + responder.doCommandCalls = []; +} + +- (void)testInterpretKeyEvents +{ + var tests = [ + CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(pageUp:), + CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(pageDown:), + CPKeyCodes.LEFT, CPLeftArrowFunctionKey, @selector(moveLeft:), + CPKeyCodes.RIGHT, CPRightArrowFunctionKey, @selector(moveRight:), + CPKeyCodes.UP, CPUpArrowFunctionKey, @selector(moveUp:), + CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), + CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), + CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), + CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), + CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) + ]; + + for (var i=0; i Date: Fri, 11 Jun 2010 12:47:05 -0400 Subject: [PATCH 24/61] Don't test keyCodes directly in CPResponder now that we have proper key equivalent characters. --- AppKit/CPResponder.j | 64 ++++++++++++++++------------------ Tests/AppKit/CPResponderTest.j | 1 + 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 746e4e992..4b81635d1 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -22,7 +22,6 @@ @import - CPDeleteKeyCode = 8; CPTabKeyCode = 9; CPReturnKeyCode = 13; @@ -39,7 +38,7 @@ CPDeleteForwardKeyCode = 46; /*! @ingroup appkit @class CPResponder - + Subclasses of CPResonder can be part of the responder chain. */ @implementation CPResponder : CPObject @@ -107,39 +106,36 @@ CPDeleteForwardKeyCode = 46; { var event = events[index]; - switch([event keyCode]) + switch([[event characters] characterAtIndex:0]) { - case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)]; - break; - case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)]; - break; - case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)]; - break; - case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)]; - break; - case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)]; - break; - case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)]; - break; - case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)]; - break; - case CPReturnKeyCode: - case 3: [self doCommandBySelector:@selector(insertLineBreak:)]; - break; - - case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)]; - break; + case CPPageUpFunctionKey: [self doCommandBySelector:@selector(pageUp:)]; + break; + case CPPageDownFunctionKey: [self doCommandBySelector:@selector(pageDown:)]; + break; + case CPLeftArrowFunctionKey: [self doCommandBySelector:@selector(moveLeft:)]; + break; + case CPRightArrowFunctionKey: [self doCommandBySelector:@selector(moveRight:)]; + break; + case CPUpArrowFunctionKey: [self doCommandBySelector:@selector(moveUp:)]; + break; + case CPDownArrowFunctionKey: [self doCommandBySelector:@selector(moveDown:)]; + break; + case CPDeleteCharacter: [self doCommandBySelector:@selector(deleteBackward:)]; + break; + case CPCarriageReturnCharacter: + case CPNewlineCharacter: [self doCommandBySelector:@selector(insertLineBreak:)]; + break; - case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask; + case CPEscapeFunctionKey: [self doCommandBySelector:@selector(cancel:)]; + break; - if (!shift) - [self doCommandBySelector:@selector(insertTab:)]; - else - [self doCommandBySelector:@selector(insertBackTab:)]; + case CPTabCharacter: if (!([event modifierFlags] & CPShiftKeyMask)) + [self doCommandBySelector:@selector(insertTab:)]; + else + [self doCommandBySelector:@selector(insertBackTab:)]; + break; - break; - - default: [self insertText:[event characters]]; + default: [self insertText:[event characters]]; } } } @@ -316,7 +312,7 @@ CPDeleteForwardKeyCode = 46; if([self respondsToSelector:aSelector]) { [self performSelector:aSelector withObject:anObject]; - + return YES; } @@ -367,10 +363,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey"; - (id)initWithCoder:(CPCoder)aCoder { self = [super init]; - + if (self) _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; - + return self; } diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j index 891d3076b..eab226833 100644 --- a/Tests/AppKit/CPResponderTest.j +++ b/Tests/AppKit/CPResponderTest.j @@ -29,6 +29,7 @@ CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), + 0, CPNewlineCharacter, @selector(insertLineBreak:), CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) ]; From 5c5412db67bde3c9f5096a881d6a3266ea87b419 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 10 Jun 2010 00:07:53 -0400 Subject: [PATCH 25/61] Make didChangeValueForKey work even if willChangeValueForKey was not called. --- Foundation/CPKeyValueObserving.j | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 12f2f6e51..0ff9fdd26 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -426,6 +426,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, } else { + // The isBefore path may not have been called as would happen if didChangeX + // was called alone. + if (!changes) + changes = [CPDictionary new]; + [changes removeObjectForKey:CPKeyValueChangeNotificationIsPriorKey]; var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey]; From fed39694f69093e8deb13222d94f1e90d43fd19a Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sat, 12 Jun 2010 18:23:51 -0700 Subject: [PATCH 26/61] Improve the handling of key window's losing their status. --- AppKit/CPWindow/CPWindow.j | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index caf713d63..41e410a4b 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1942,10 +1942,16 @@ CPTexturedBackgroundWindowMask else { var mainMenu = [CPApp mainMenu], - menuWindow = mainMenu ? mainMenu._menuWindow : nil; + menuBarClass = objj_getClass("_CPMenuBarWindow"), + menuWindow; + for (var i = 0; i < windowCount; i++) { var currentWindow = allWindows[i]; + + if ([currentWindow isKindOfClass:menuBarClass]) + menuWindow = currentWindow; + if (currentWindow === self || currentWindow === menuWindow) continue; @@ -1971,10 +1977,16 @@ CPTexturedBackgroundWindowMask else { var mainMenu = [CPApp mainMenu], - menuWindow = mainMenu ? mainMenu._menuWindow : nil; + menuBarClass = objj_getClass("_CPMenuBarWindow"), + menuWindow; + for (var i = 0; i < windowCount; i++) { var currentWindow = allWindows[i]; + + if ([currentWindow isKindOfClass:menuBarClass]) + menuWindow = currentWindow; + if (currentWindow === self || currentWindow === menuWindow) continue; From 9a3c2d5311a98d15f56733c620528c3981234285 Mon Sep 17 00:00:00 2001 From: Francisco Ryan Tolmasky I Date: Sat, 12 Jun 2010 17:46:38 -0700 Subject: [PATCH 27/61] Fix for scrolling affecting background windows with NativeHost. Reviewed by me. --- Tools/NativeHost/Application.m | 2 ++ Tools/NativeHost/WebWindow.m | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Tools/NativeHost/Application.m b/Tools/NativeHost/Application.m index 4dbb8a397..2234f307d 100644 --- a/Tools/NativeHost/Application.m +++ b/Tools/NativeHost/Application.m @@ -15,6 +15,8 @@ - (void)sendEvent:(NSEvent *)anEvent { + [WebWindow enableAllWindows]; + NSWindow * window = [anEvent window]; if (!window || [window isKindOfClass:[WebWindow class]]) diff --git a/Tools/NativeHost/WebWindow.m b/Tools/NativeHost/WebWindow.m index 631e73a72..122aa453b 100644 --- a/Tools/NativeHost/WebWindow.m +++ b/Tools/NativeHost/WebWindow.m @@ -18,9 +18,6 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e // It's dangerous to fail in this code: could disable mousedown system-wide. So just try catch it all. @try { - [DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)]; - [DisabledWindows removeAllObjects]; - if (type == kCGEventLeftMouseDown) { CGPoint location = CGEventGetLocation(event); @@ -55,6 +52,12 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e @implementation WebWindow ++ (void)enableAllWindows +{ + [DisabledWindows makeObjectsPerformSelector:@selector(stopIgnoringMouseEvents)]; + [DisabledWindows removeAllObjects]; +} + + (void)initialize { if (self != [WebWindow class]) @@ -117,8 +120,9 @@ CGEventRef headTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef e [self setBackgroundColor:[NSColor clearColor]]; [self setOpaque:NO]; + [self setIgnoresMouseEvents:NO]; [self setReleasedWhenClosed:YES]; - [super setHasShadow:NO]; + [super setHasShadow:NO]; } return self; From 2f58517ce57366658c5cbc8c29b980137ae8b1df Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 15 Jun 2010 09:28:22 -0700 Subject: [PATCH 28/61] Request headers should be set after the request is re-opened. Closes #701. --- Objective-J/CFHTTPRequest.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Objective-J/CFHTTPRequest.js b/Objective-J/CFHTTPRequest.js index d4007f585..2ef8c721f 100644 --- a/Objective-J/CFHTTPRequest.js +++ b/Objective-J/CFHTTPRequest.js @@ -219,12 +219,6 @@ CFHTTPRequest.prototype.open = function(/*String*/ aMethod, /*String*/ aURL, /*B CFHTTPRequest.prototype.send = function(/*Object*/ aBody) { - for (var i in this._requestHeaders) - { - if (this._requestHeaders.hasOwnProperty(i)) - this._nativeRequest.setRequestHeader(i, this._requestHeaders[i]); - } - if (!this._isOpen) { delete this._nativeRequest.onreadystatechange; @@ -232,6 +226,12 @@ CFHTTPRequest.prototype.send = function(/*Object*/ aBody) this._nativeRequest.onreadystatechange = this._stateChangeHandler; } + for (var i in this._requestHeaders) + { + if (this._requestHeaders.hasOwnProperty(i)) + this._nativeRequest.setRequestHeader(i, this._requestHeaders[i]); + } + if (this._mimeType && "overrideMimeType" in this._nativeRequest) this._nativeRequest.overrideMimeType(this._mimeType); From 16be03b16296ba1f7c4b3b069da08cc48cf9a100 Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Tue, 15 Jun 2010 01:58:09 -0400 Subject: [PATCH 29/61] If first segment is enabled and mode is one-only, _selectedSegment is correctly set to 0 --- Tools/nib2cib/NSSegmentedControl.j | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tools/nib2cib/NSSegmentedControl.j b/Tools/nib2cib/NSSegmentedControl.j index 737132f80..df3145d20 100644 --- a/Tools/nib2cib/NSSegmentedControl.j +++ b/Tools/nib2cib/NSSegmentedControl.j @@ -98,6 +98,9 @@ _selectedSegment = [aCoder decodeIntForKey:"NSSelectedSegment"] || -1; _segmentStyle = [aCoder decodeIntForKey:"NSSegmentStyle"]; _trackingMode = [aCoder decodeIntForKey:"NSTrackingMode"] || CPSegmentSwitchTrackingSelectOne; + + if (_trackingMode == CPSegmentSwitchTrackingSelectOne && _selectedSegment == -1) + _selectedSegment = 0; } return self; From 17a8be1ae67c47168fa328ff1712a81d05ccff2d Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Tue, 15 Jun 2010 19:20:48 -0700 Subject: [PATCH 30/61] Return the actually last selected row in CPTableView. Closes 716. --- AppKit/CPTableView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 3a2b0f0d9..e889cfa28 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -1020,7 +1020,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; - (int)selectedRow { - return [_selectedRowIndexes lastIndex]; + return _lastSelectedRow; } - (CPIndexSet)selectedRowIndexes From eaf4fa240f29755271b6b1890994713b2e137220 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 16 Jun 2010 14:16:17 +0200 Subject: [PATCH 31/61] slightly delay triggering the action in CPControl performClick: to make sure the click is always visible --- AppKit/CPControl.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 7de6719c4..3a1ec1200 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -337,13 +337,13 @@ var CPControlBlackColor = [CPColor blackColor]; [self highlight:YES]; [self setState:[self nextState]]; - [self sendAction:[self action] to:[self target]]; [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; } - (void)unhighlightButtonTimerDidFinish:(id)sender { + [self sendAction:[self action] to:[self target]]; [self highlight:NO]; } From f40fc321fe007586aaeb5c30668b8fe2430b3af3 Mon Sep 17 00:00:00 2001 From: Klaas Pieter Annema Date: Wed, 16 Jun 2010 14:17:58 +0200 Subject: [PATCH 32/61] Make the window perform it's defaults button's key equivalent after the default keyDown messages are handled --- AppKit/CPButton.j | 20 ++++++++++++++++++++ AppKit/CPWindow/CPWindow.j | 28 +++++++++++++++++----------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/AppKit/CPButton.j b/AppKit/CPButton.j index 75206a02c..3bc21844b 100644 --- a/AppKit/CPButton.j +++ b/AppKit/CPButton.j @@ -569,9 +569,25 @@ CPButtonStateMixed = CPThemeState("mixed"); */ - (void)setKeyEquivalent:(CPString)aString { + // Check if the key equivalent is the enter key + // Treat \r and \n as the same key equivalent. See issue #710. + if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter) + [[self window] setDefaultButton:self]; + else if ([[self window] defaultButton] === self) + [[self window] setDefaultButton:NO]; + _keyEquivalent = aString || @""; } +- (void)viewWillMoveToWindow:(CPWindow)aWindow +{ + if ([[self window] defaultButton] === self) + [[self window] setDefaultButton:nil]; + + if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter) + [aWindow setDefaultButton:self]; +} + /*! Returns the keyboard shortcut for this button. */ @@ -602,6 +618,10 @@ CPButtonStateMixed = CPThemeState("mixed"); */ - (BOOL)performKeyEquivalent:(CPEvent)anEvent { + // Don't handle the key equivalent for the default window because the window will handle it for us + if ([[self window] defaultButton] === self) + return NO; + if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]]) return NO; diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 41e410a4b..effa1788c 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1377,7 +1377,15 @@ CPTexturedBackgroundWindowMask switch (type) { case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; - case CPKeyDown: return [[self firstResponder] keyDown:anEvent]; + + case CPKeyDown: [[self firstResponder] keyDown:anEvent]; + + // Trigger the default button if needed + if (![self disableKeyEquivalentForDefaultButton]) + if ([anEvent _triggersKeyEquivalent:[[self defaultButton] keyEquivalent] withModifierMask:[[self defaultButton] keyEquivalentModifierMask]]) + [[self defaultButton] performClick:self]; + + return; case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; @@ -2250,7 +2258,7 @@ CPTexturedBackgroundWindowMask return NO; } -- (void)performKeyEquivalent:(CPEvent)anEvent +- (BOOL)performKeyEquivalent:(CPEvent)anEvent { // FIXME: should we be starting at the root, in other words _windowView? // The evidence seems to point to no... @@ -2261,14 +2269,11 @@ CPTexturedBackgroundWindowMask { // It's not clear why we do performKeyEquivalent again here... // Perhaps to allow something to happen between sendEvent: and keyDown:? - if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent]) - [self interpretKeyEvents:[anEvent]]; -} + if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) + return; -- (void)insertNewline:(id)sender -{ - if (_defaultButton && _defaultButtonEnabled) - [_defaultButton performClick:nil]; + // Interpret the key events + [self interpretKeyEvents:[anEvent]]; } - (void)insertTab:(id)sender @@ -2381,10 +2386,11 @@ CPTexturedBackgroundWindowMask - (void)setDefaultButton:(CPButton)aButton { + if (_defaultButton === aButton) + return; + [_defaultButton setDefaultButton:NO]; - _defaultButton = aButton; - [_defaultButton setDefaultButton:YES]; } From 1b174b86cadeeeec7e42a6c7afa22dd2ac8b39c1 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 16 Jun 2010 08:14:04 -0700 Subject: [PATCH 33/61] Buttons should also be re-centered after their height is changed in nib2cib. --- Tools/nib2cib/NSButton.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 130e4f395..6bbb426c0 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -93,10 +93,11 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _bezelStyle = CPHUDBezelStyle; } - if ([cell isBordered]) + if ([cell isBordered] && _frame.size.height === 32.0) { CPLog.info("Adjusting CPButton height from " +_frame.size.height+ " / " + _bounds.size.height+" to " + 24); _frame.size.height = 24.0; + _frame.origin.y += 4.0; _bounds.size.height = 24.0; } } From 6a43c544eba40d3912b50b9482e3b0f0306b97fb Mon Sep 17 00:00:00 2001 From: Aparajita Fishman Date: Mon, 14 Jun 2010 20:01:30 -0400 Subject: [PATCH 34/61] Added support for reading max rows/columns from cib --- AppKit/CPCollectionView.j | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 80957124c..084686395 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -847,11 +847,13 @@ @end -var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", - CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", - CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", - CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", - CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; +var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", + CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", + CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", + CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey", + CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey", + CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey", + CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey"; @implementation CPCollectionView (CPCoding) @@ -871,6 +873,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); + + _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0; + _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0; _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey]; @@ -898,6 +903,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey]; + [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey]; + [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey]; + [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; From db3514a2c1c9bccf4527a26acad9c5be82071a2f Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:40:35 -0400 Subject: [PATCH 35/61] Only allow a single window frame animation at a time; stop the previous animation before starting a new one. This allows e.g. a sheet animating open to 'turn around' and animate right back out. Fixed: if a sheet was closed before it finished animating open, for example by hitting a keyboard equivalent immediately, CPWindow would crash with "Uncaught TypeError: Cannot read property 'sheet' of null". --- AppKit/CPWindow/CPWindow.j | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index effa1788c..7e619bd57 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -320,6 +320,8 @@ var CPWindowSaveImage = nil, CPDictionary _sheetContext; CPWindow _parentView; BOOL _isSheet; + + _CPWindowFrameAnimation _frameAnimation; } /* @@ -659,9 +661,10 @@ CPTexturedBackgroundWindowMask if (shouldAnimate) { - var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + [_frameAnimation stopAnimation]; + _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - [animation startAnimation]; + [_frameAnimation startAnimation]; } else { @@ -2074,11 +2077,12 @@ CPTexturedBackgroundWindowMask - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve { - var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; - [animation setDelegate:delegate]; - [animation setAnimationCurve:curve]; - [animation setDuration:duration]; - [animation startAnimation]; + [_frameAnimation stopAnimation]; + _frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; + [_frameAnimation setDelegate:delegate]; + [_frameAnimation setAnimationCurve:curve]; + [_frameAnimation setDuration:duration]; + [_frameAnimation startAnimation]; } /* @ignore */ From 685c3c985318de263ca70ba66e3137f43bf45333 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sun, 13 Jun 2010 02:13:46 -0400 Subject: [PATCH 36/61] Don't add no-ops to the undo stack when using automatic undo manager mode. This is necessary when used together with bindings since controls issue reverse binding updates whenever editing ends, which would add a 'do nothing' undo entry on the stack in cases where nothing changed. --- Foundation/CPUndoManager.j | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index f07247589..9e15c891b 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -726,6 +726,12 @@ if (_currentGroup == nil) change:(CPDictionary)aChange context:(id)aContext { + // Don't add no-ops to the undo stack. + var before = [aChange valueForKey:CPKeyValueChangeOldKey], + after = [aChange valueForKey:CPKeyValueChangeNewKey]; + if (before === after || [before isEqual:after]) + return; + [[self prepareWithInvocationTarget:anObject] applyChange:[aChange inverseChangeDictionary] toKeyPath:aKeyPath]; From c80735821621fd2a5af4b2609ebbec58803fa46c Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:50:31 -0400 Subject: [PATCH 37/61] Support non Objective-J objects in CPUndoManager's no-op check for auto undo. --- Foundation/CPUndoManager.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index 9e15c891b..dea9c74a4 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -729,7 +729,7 @@ if (_currentGroup == nil) // Don't add no-ops to the undo stack. var before = [aChange valueForKey:CPKeyValueChangeOldKey], after = [aChange valueForKey:CPKeyValueChangeNewKey]; - if (before === after || [before isEqual:after]) + if (before === after || (after !== nil && after.isa && [before isEqual:after])) return; [[self prepareWithInvocationTarget:anObject] From f2c01cbbbdf77f8b8c02719e1ea311f49d8d3562 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Tue, 15 Jun 2010 22:59:37 -0400 Subject: [PATCH 38/61] In CPUndoManager, handle the edge cases if an object changes from being an Objective-J object to being just a JS object. Also handle the case where an Objective-J object could theoretically compare equal to nil - CPNull isEqual:. --- Foundation/CPUndoManager.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Foundation/CPUndoManager.j b/Foundation/CPUndoManager.j index dea9c74a4..7f0b58a83 100644 --- a/Foundation/CPUndoManager.j +++ b/Foundation/CPUndoManager.j @@ -729,7 +729,7 @@ if (_currentGroup == nil) // Don't add no-ops to the undo stack. var before = [aChange valueForKey:CPKeyValueChangeOldKey], after = [aChange valueForKey:CPKeyValueChangeNewKey]; - if (before === after || (after !== nil && after.isa && [before isEqual:after])) + if (before === after || (before !== nil && before.isa && (after === nil || after.isa) && [before isEqual:after])) return; [[self prepareWithInvocationTarget:anObject] From 19d5431f609b3cead32590dc1c372746be108d14 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 16 Jun 2010 08:54:30 -0700 Subject: [PATCH 39/61] Revert "slightly delay triggering the action in CPControl performClick: to make sure the click is always visible" This reverts commit eaf4fa240f29755271b6b1890994713b2e137220. --- AppKit/CPControl.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPControl.j b/AppKit/CPControl.j index 3a1ec1200..7de6719c4 100644 --- a/AppKit/CPControl.j +++ b/AppKit/CPControl.j @@ -337,13 +337,13 @@ var CPControlBlackColor = [CPColor blackColor]; [self highlight:YES]; [self setState:[self nextState]]; + [self sendAction:[self action] to:[self target]]; [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO]; } - (void)unhighlightButtonTimerDidFinish:(id)sender { - [self sendAction:[self action] to:[self target]]; [self highlight:NO]; } From 7414d1407ff279b1fc1953024f96b62a2683fde0 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Wed, 16 Jun 2010 13:59:25 -0500 Subject: [PATCH 40/61] Moved tracking of last selected row index to selectRowIndexes: in tableview. --- AppKit/CPTableView.j | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index e889cfa28..f67079a90 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -909,6 +909,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; else _selectedRowIndexes = [rows copy]; + // update last selected row + _lastSelectedRow = ([rows count] > 0) ? [rows lastIndex] : -1; + [self _updateHighlightWithOldRows:previousSelectedIndexes newRows:_selectedRowIndexes]; [_tableDrawView display]; // FIXME: should be setNeedsDisplayInRect:enclosing rect of new (de)selected rows // but currently -drawRect: is not implemented here @@ -3268,8 +3271,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; } } - _lastSelectedRow = ([newSelection count] > 0) ? aRow : -1; - // if empty selection is not allowed and the new selection has nothing selected, abort if (!_allowsEmptySelection && [newSelection count] === 0) return; From bd06b8a86723239a285e39a298ade347ca9a6332 Mon Sep 17 00:00:00 2001 From: nciagra Date: Wed, 16 Jun 2010 22:02:40 -0400 Subject: [PATCH 41/61] Modifier keys will fire flagsChanged: instead of keyDown: and keyUp:, like Cocoa does. --- AppKit/CPResponder.j | 9 +++++++ AppKit/CPWindow/CPWindow.j | 2 ++ AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 28 ++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 4b81635d1..6836194ec 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -236,6 +236,15 @@ CPDeleteForwardKeyCode = 46; [_nextResponder performSelector:_cmd withObject:anEvent]; } +/*! + Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on). + @param anEvent information about the key press +*/ +- (void)flagsChanged:(CPEvent)anEvent +{ + [_nextResponder performSelector:_cmd withObject:anEvent]; +} + /* FIXME This description is bad. Based on \c anEvent, the receiver should simulate the event. diff --git a/AppKit/CPWindow/CPWindow.j b/AppKit/CPWindow/CPWindow.j index 7e619bd57..75650792f 100644 --- a/AppKit/CPWindow/CPWindow.j +++ b/AppKit/CPWindow/CPWindow.j @@ -1379,6 +1379,8 @@ CPTexturedBackgroundWindowMask switch (type) { + case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent]; + case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; case CPKeyDown: [[self firstResponder] keyDown:anEvent]; diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 2132d0c80..430341f97 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -156,6 +156,14 @@ KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey; KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey; +var ModifierKeyCodes = [ + CPKeyCodes.META, + CPKeyCodes.MAC_FF_META, + CPKeyCodes.CTRL, + CPKeyCodes.ALT, + CPKeyCodes.SHIFT +]; + var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; @implementation CPPlatformWindow (DOM) @@ -607,8 +615,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; - (void)keyEvent:(DOMEvent)aDOMEvent { var event, - timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(), - sourceElement = (aDOMEvent.target || aDOMEvent.srcElement), + timestamp = aDOMEvent.timeStamp || new Date(), + sourceElement = aDOMEvent.target || aDOMEvent.srcElement, windowNumber = [[CPApp keyWindow] windowNumber], modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) | (aDOMEvent.ctrlKey ? CPControlKeyMask : 0) | @@ -627,7 +635,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; switch (aDOMEvent.type) { case "keydown": // Grab and store the keycode now since it is correct and consistent at this point. - if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap) + if (aDOMEvent.keyCode in MozKeyCodeToKeyCodeMap) _keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode]; else _keyCode = aDOMEvent.keyCode; @@ -639,7 +647,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (_keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = YES; - if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) + if ([ModifierKeyCodes containsObject:_keyCode]) + { + // A modifier key will never fire keypress. We don't need to do any other processing so we just fire it here and break. + event = [CPEvent keyEventWithType:CPFlagsChanged location:location modifierFlags:modifierFlags + timestamp:timestamp windowNumber:windowNumber context:nil + characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:_keyCode]; + + break; + } + else if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) { //we are simply going to skip all keypress events that use cmd/ctrl key //this lets us be consistent in all browsers and send on the keydown @@ -728,6 +745,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; if (keyCode === CPKeyCodes.CAPS_LOCK) _capsLockActive = NO; + if ([ModifierKeyCodes containsObject:keyCode]) + break; + var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), charactersIgnoringModifiers = characters.toLowerCase(); From 96fc34c00ea669fa4570178bdd4135097d9f7837 Mon Sep 17 00:00:00 2001 From: nciagra Date: Wed, 16 Jun 2010 22:03:31 -0400 Subject: [PATCH 42/61] CPResponder -interpretKeyEvents: will only call -insertText: if the Command and Control keys are not being held. --- AppKit/CPResponder.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 6836194ec..9760e5449 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -135,7 +135,8 @@ CPDeleteForwardKeyCode = 46; [self doCommandBySelector:@selector(insertBackTab:)]; break; - default: [self insertText:[event characters]]; + default: if (!([event modifierFlags] & (CPCommandKeyMask | CPControlKeyMask))) + [self insertText:[event characters]]; } } } From f09193ce07e60c3d1e4befee793eb8fdb203d3b9 Mon Sep 17 00:00:00 2001 From: nciagra Date: Thu, 17 Jun 2010 00:17:52 -0400 Subject: [PATCH 43/61] Properly differentiate between special keys and normal keys in key handlers. --- AppKit/Platform/DOM/CPPlatformWindow+DOM.j | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j index 430341f97..0a51a76a0 100644 --- a/AppKit/Platform/DOM/CPPlatformWindow+DOM.j +++ b/AppKit/Platform/DOM/CPPlatformWindow+DOM.j @@ -640,7 +640,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; else _keyCode = aDOMEvent.keyCode; - var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase(); + var characters; + + // Is this a special key? + if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0) + characters = KeyCodesToFunctionUnicodeMap[_keyCode]; + + if (!characters) + characters = String.fromCharCode(_keyCode).toLowerCase(); + overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters; // check for caps lock state @@ -713,8 +721,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; _lastKey = keyCode; _charCodes[keyCode] = charCode; - var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode), - charactersIgnoringModifiers = characters.toLowerCase(); + var characters = overrideCharacters; + // Is this a special key? + if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)) + characters = KeyCodesToFunctionUnicodeMap[charCode]; + + if (!characters) + characters = String.fromCharCode(charCode); + + charactersIgnoringModifiers = characters.toLowerCase(); // FIXME: This isn't correct. It SHOULD include Shift. // Safari won't send proper capitalization during cmd-key events if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive)) @@ -722,7 +737,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop]; event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags timestamp:timestamp windowNumber:windowNumber context:nil - characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode]; + characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:charCode]; if (isNativePasteEvent) { From 997a305d35849fc20969ec2e7d883c5ac1b84ef6 Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 10:40:15 -0400 Subject: [PATCH 44/61] Added CPKeyBinding for a dynamic key binding system. --- AppKit/AppKit.j | 1 + AppKit/CPKeyBinding.j | 233 ++++++++++++++++++++++++++++++++++++++++++ AppKit/CPResponder.j | 44 +++----- 3 files changed, 248 insertions(+), 30 deletions(-) create mode 100644 AppKit/CPKeyBinding.j diff --git a/AppKit/AppKit.j b/AppKit/AppKit.j index 1feb31525..9c820be65 100644 --- a/AppKit/AppKit.j +++ b/AppKit/AppKit.j @@ -55,6 +55,7 @@ @import "CPGeometry.j" @import "CPImage.j" @import "CPImageView.j" +@import "CPKeyBinding.j" @import "CPMenu.j" @import "CPMenuItem.j" @import "CPOpenPanel.j" diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j new file mode 100644 index 000000000..e68b16c3c --- /dev/null +++ b/AppKit/CPKeyBinding.j @@ -0,0 +1,233 @@ +/* + * CPKeyBinding.j + * AppKit + * + * Created by Nicholas Small. + * Copyright 2010, 280 North, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import + + +CPStandardKeyBindings = { + @"@.": @"cancelOperation:", + + @"^a": @"moveToBeginningOfParagraph:", + @"^$a": @"moveToBeginningOfParagraphAndModifySelection:", + @"^b": @"moveBackward:", + @"^$b": @"moveBackwardAndModifySelection:", + @"^~$b": @"moveWordBackwardAndModifySelection:", + @"^d": @"deleteForward:", + @"^e": @"moveToEndOfParagraph:", + @"^$e": @"moveToEndOfParagraphAndModifySelection:", + @"^f": @"moveForward:", + @"^$f": @"moveForwardAndModifySelection:", + @"^~f": @"moveWordForward:", + @"^~$f": @"moveWordForwardAndModifySelection:", + @"^h": @"deleteBackward:", + @"^k": @"deleteToEndOfParagraph:", + @"^l": @"centerSelectionInVisibleArea:", + @"^n": @"moveDown:", + @"^$n": @"moveDownAndModifySelection:", + @"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"], + @"^p": @"moveUp:", + @"^$p": @"moveUpAndModifySelection:", + @"^t": @"transpose:", + @"^v": @"pageDown:", + @"^v": @"pageDownAndModifySelection:", + @"^y": @"yank:" +}; + +CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:"; +CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:"; +CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:"; +CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:"; +CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:"; +CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:"; +CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:"; + +CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:"; +CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:"; +CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:"; +CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:"; +CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:"; +CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:"; +CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:"; + +CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:"; +CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:"; + +CPStandardKeyBindings[CPTabCharacter] = @"insertTab:"; +CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:"; +CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:"; +CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:"; +CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:"; + +CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:"; +CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:"; +CPStandardKeyBindings[CPF5FunctionKey] = @"complete:"; + +CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:"; +CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:"; +CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:"; +CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:"; +CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:"; +CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:"; +CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:"; + +CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:"; +CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:"; +CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:"; +CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:"; +CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:"; +CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:"; +CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:"; + +CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:"; +CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"]; +CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:"; +CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:"; +CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:"; + +CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:"; +CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"]; +CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:"; +CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:"; +CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:"; +CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:"; +CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:"; +CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:"; +CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:"; + +CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:"; +CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:"; +CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:"; +CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:"; + +CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:"; +CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:"; +CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:"; +CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:"; +CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:"; +CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:"; + +var CPKeyBindingCache = []; + +@implementation CPKeyBinding : CPObject +{ + CPString _key; + unsigned _modifierFlags; + + CPArray _selectors; +} + ++ (void)initialize +{ + if ([self class] !== CPKeyBinding) + return; + + [self createKeyBindingsFromJSObject:CPStandardKeyBindings]; +} + ++ (void)createKeyBindingsFromJSObject:(JSObject)anObject +{ + var binding; + for (binding in anObject) + { + var components = binding.split(@""), + modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) | + ([components containsObject:@"^"] ? CPControlKeyMask : 0) | + ([components containsObject:@"~"] ? CPAlternateKeyMask : 0) | + ([components containsObject:@"@"] ? CPCommandKeyMask : 0); + + var selectors = anObject[binding]; + if (![selectors isKindOfClass:CPArray]) + selectors = [selectors]; + + var keyBinding = [[self alloc] initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors]; + [self cacheKeyBinding:keyBinding]; + } +} + ++ (void)cacheKeyBinding:(CPKeyBinding)aBinding +{ + if (aBinding) + [CPKeyBindingCache addObject:aBinding]; +} + ++ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag +{ + var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil]; + for (var i = 0, count = CPKeyBindingCache.length; i < count; i++) + { + var binding = CPKeyBindingCache[i]; + if ([binding isEqual:tempBinding]) + return binding; + } +} + ++ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag +{ + return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors]; +} + +- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors +{ + self = [super init]; + + if (self) + { + _key = aKey; + _modifierFlags = aFlag; + + _selectors = selectors; + } + + return self; +} + +- (CPString)key +{ + return _key; +} + +- (unsigned)modifierFlags +{ + return _modifierFlags; +} + +- (CPArray)selectors +{ + return _selectors; +} + +- (BOOL)isEqual:(CPKeyBinding)rhs +{ + return _key === [rhs key] && _modifierFlags === [rhs modifierFlags]; +} + +@end diff --git a/AppKit/CPResponder.j b/AppKit/CPResponder.j index 9760e5449..08b27616e 100644 --- a/AppKit/CPResponder.j +++ b/AppKit/CPResponder.j @@ -104,40 +104,24 @@ CPDeleteForwardKeyCode = 46; for (; index < count; ++index) { - var event = events[index]; + var event = events[index], + modifierFlags = [event modifierFlags], + character = [event charactersIgnoringModifiers], + selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags]; - switch([[event characters] characterAtIndex:0]) + if (selectorNames) { - case CPPageUpFunctionKey: [self doCommandBySelector:@selector(pageUp:)]; - break; - case CPPageDownFunctionKey: [self doCommandBySelector:@selector(pageDown:)]; - break; - case CPLeftArrowFunctionKey: [self doCommandBySelector:@selector(moveLeft:)]; - break; - case CPRightArrowFunctionKey: [self doCommandBySelector:@selector(moveRight:)]; - break; - case CPUpArrowFunctionKey: [self doCommandBySelector:@selector(moveUp:)]; - break; - case CPDownArrowFunctionKey: [self doCommandBySelector:@selector(moveDown:)]; - break; - case CPDeleteCharacter: [self doCommandBySelector:@selector(deleteBackward:)]; - break; - case CPCarriageReturnCharacter: - case CPNewlineCharacter: [self doCommandBySelector:@selector(insertLineBreak:)]; - break; + for (var s = 0, scount = selectorNames.length; s < scount; s++) + { + var selector = selectorNames[s]; + if (!selector) + continue; - case CPEscapeFunctionKey: [self doCommandBySelector:@selector(cancel:)]; - break; - - case CPTabCharacter: if (!([event modifierFlags] & CPShiftKeyMask)) - [self doCommandBySelector:@selector(insertTab:)]; - else - [self doCommandBySelector:@selector(insertBackTab:)]; - break; - - default: if (!([event modifierFlags] & (CPCommandKeyMask | CPControlKeyMask))) - [self insertText:[event characters]]; + [self doCommandBySelector:CPSelectorFromString(selector)]; + } } + else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)]) + [self insertText:[event characters]]; } } From cbb9602f9e3f2a98ceeabe252496915d95fbe80e Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 11:50:33 -0400 Subject: [PATCH 45/61] Better caching of key bindings. --- AppKit/CPKeyBinding.j | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j index e68b16c3c..77cdde0df 100644 --- a/AppKit/CPKeyBinding.j +++ b/AppKit/CPKeyBinding.j @@ -135,7 +135,7 @@ CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:"; CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:"; CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:"; -var CPKeyBindingCache = []; +var CPKeyBindingCache = {}; @implementation CPKeyBinding : CPObject { @@ -143,6 +143,8 @@ var CPKeyBindingCache = []; unsigned _modifierFlags; CPArray _selectors; + + CPString _cacheName; } + (void)initialize @@ -175,19 +177,16 @@ var CPKeyBindingCache = []; + (void)cacheKeyBinding:(CPKeyBinding)aBinding { - if (aBinding) - [CPKeyBindingCache addObject:aBinding]; + if (!aBinding) + return; + + CPKeyBindingCache[[aBinding _cacheName]] = aBinding; } + (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag { var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil]; - for (var i = 0, count = CPKeyBindingCache.length; i < count; i++) - { - var binding = CPKeyBindingCache[i]; - if ([binding isEqual:tempBinding]) - return binding; - } + return CPKeyBindingCache[[tempBinding _cacheName]]; } + (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag @@ -205,6 +204,23 @@ var CPKeyBindingCache = []; _modifierFlags = aFlag; _selectors = selectors; + + // We normalize our key binding string in order to properly cache it. + // We want to ensure the modifiers are always in the same order. + var cacheName = []; + + if (_modifierFlags & CPCommandKeyMask) + cacheName.push(@"@"); + if (_modifierFlags & CPControlKeyMask) + cacheName.push(@"^"); + if (_modifierFlags & CPAlternateKeyMask) + cacheName.push(@"~"); + if (_modifierFlags & CPShiftKeyMask) + cacheName.push(@"$"); + + cacheName.push(_key); + + _cacheName = cacheName.join(@""); } return self; @@ -225,6 +241,11 @@ var CPKeyBindingCache = []; return _selectors; } +- (CPString)_cacheName +{ + return _cacheName; +} + - (BOOL)isEqual:(CPKeyBinding)rhs { return _key === [rhs key] && _modifierFlags === [rhs modifierFlags]; From b37f5b4143509b6f82ccb4bac95da45e41cfe055 Mon Sep 17 00:00:00 2001 From: nciagra Date: Fri, 18 Jun 2010 14:18:29 -0400 Subject: [PATCH 46/61] Fix CPResponderTest. --- Tests/AppKit/CPResponderTest.j | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Tests/AppKit/CPResponderTest.j b/Tests/AppKit/CPResponderTest.j index eab226833..2cfa482f3 100644 --- a/Tests/AppKit/CPResponderTest.j +++ b/Tests/AppKit/CPResponderTest.j @@ -21,16 +21,16 @@ - (void)testInterpretKeyEvents { var tests = [ - CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(pageUp:), - CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(pageDown:), + CPKeyCodes.PAGE_UP, CPPageUpFunctionKey, @selector(scrollPageUp:), + CPKeyCodes.PAGE_DOWN, CPPageDownFunctionKey, @selector(scrollPageDown:), CPKeyCodes.LEFT, CPLeftArrowFunctionKey, @selector(moveLeft:), CPKeyCodes.RIGHT, CPRightArrowFunctionKey, @selector(moveRight:), CPKeyCodes.UP, CPUpArrowFunctionKey, @selector(moveUp:), CPKeyCodes.DOWN, CPDownArrowFunctionKey, @selector(moveDown:), CPKeyCodes.BACKSPACE, CPDeleteCharacter, @selector(deleteBackward:), - CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertLineBreak:), - 0, CPNewlineCharacter, @selector(insertLineBreak:), - CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancel:), + CPKeyCodes.ENTER, CPCarriageReturnCharacter, @selector(insertNewline:), + 0, CPNewlineCharacter, @selector(insertNewline:), + CPKeyCodes.ESC, CPEscapeFunctionKey, @selector(cancelOperation:), CPKeyCodes.TAB, CPTabCharacter, @selector(insertTab:) ]; @@ -47,13 +47,16 @@ [responder interpretKeyEvents:[keyEvent]]; [self assert:[selector] equals:responder.doCommandCalls]; } +} +- (void)testInterpretKeyEventsWithModifierFlags +{ responder.doCommandCalls = []; keyEvent = [CPEvent keyEventWithType:CPKeyDown location:CGPointMakeZero() modifierFlags:CPShiftKeyMask timestamp:nil windowNumber:nil context:nil - characters:CPTabCharacter charactersIgnoringModifiers:CPTabCharacter isARepeat:NO keyCode:CPKeyCodes.TAB]; + characters:CPLeftArrowFunctionKey charactersIgnoringModifiers:CPLeftArrowFunctionKey isARepeat:NO keyCode:CPKeyCodes.LEFT]; [responder interpretKeyEvents:[keyEvent]]; - [self assert:[@selector(insertBackTab:)] equals:responder.doCommandCalls]; + [self assert:[@selector(moveLeftAndModifySelection:)] equals:responder.doCommandCalls]; } @end From 12a49d0ee120a2fe5b67a650649e1ba87a1f85c1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 18 Jun 2010 00:59:40 -0400 Subject: [PATCH 47/61] CPAlert informative text support. --- AppKit/CPAlert.j | 57 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 2d1b11ea1..500d46365 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -83,6 +83,7 @@ var CPAlertWarningImage, CPPanel _alertPanel; CPTextField _messageLabel; + CPTextField _informativeLabel; CPImageView _alertImageView; CPAlertStyle _alertStyle; @@ -140,8 +141,6 @@ var CPAlertWarningImage, [_alertPanel setFloatingPanel:YES]; [_alertPanel center]; - [_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; - var count = [_buttons count]; for(var i=0; i < count; i++) { @@ -156,19 +155,28 @@ var CPAlertWarningImage, if (!_messageLabel) { - var bounds = [[_alertPanel contentView] bounds]; - - _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)]; + _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; [_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]]; [_messageLabel setLineBreakMode:CPLineBreakByWordWrapping]; [_messageLabel setAlignment:CPJustifiedTextAlignment]; [_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; _alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)]; + + _informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; + [_informativeLabel setFont:[CPFont systemFontOfSize:12.0]]; + [_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping]; + [_informativeLabel setAlignment:CPJustifiedTextAlignment]; + [_informativeLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; } + [_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; + [_informativeLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]]; [[_alertPanel contentView] addSubview:_messageLabel]; [[_alertPanel contentView] addSubview:_alertImageView]; + [[_alertPanel contentView] addSubview:_informativeLabel]; + + [self _layoutMessage]; } /*! @@ -231,22 +239,42 @@ var CPAlertWarningImage, } /*! - Set’s the receiver’s message text, or title, to a given text. + Sets the receiver’s message text, or title, to a given text. @param messageText - Message text for the alert. */ - (void)setMessageText:(CPString)messageText { [_messageLabel setStringValue:messageText]; + [self _layoutMessage]; } -/*! - Return's the receiver's message text body. +/*! + Returns the receiver's message text body. */ - (CPString)messageText { return [_messageLabel stringValue]; } +/*! + Sets the receiver's informative text, shown below the message text. + @param informativeText - The informative text. +*/ +- (void)setInformativeText:(CPString)informativeText +{ + [_informativeLabel setStringValue:informativeText]; + // No need to call _layoutMessage - only the length of the messageText + // can affect anything there. +} + +/*! + Returns the receiver's informative text. +*/ +- (CPString)informativeText +{ + return [_informativeLabel stringValue]; +} + /*! Adds a button with a given title to the receiver. Buttons will be added starting from the right hand side of the \c CPAlert panel. @@ -281,6 +309,19 @@ var CPAlertWarningImage, [_buttons addObject:button]; } +- (void)_layoutMessage +{ + var bounds = [[_alertPanel contentView] bounds], + width = CGRectGetWidth(bounds) - 73.0, + size = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel currentValueForThemeAttribute:@"font"] inWidth:width], + contentInset = [_messageLabel currentValueForThemeAttribute:@"content-inset"], + height = size.height + contentInset.top + contentInset.bottom; + + [_messageLabel setFrame:CGRectMake(57.0, 10.0, width, height)]; + + [_informativeLabel setFrame:CGRectMake(57.0, 10.0 + height + 6.0, width, CGRectGetHeight(bounds) - height - 50.0)]; +} + /*! Displays the \c CPAlert panel as a modal dialog. The user will not be able to interact with any other controls until s/he has dismissed the alert From 4b86115d30ed54643310eb4e248b46e30ed9e35a Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Thu, 17 Jun 2010 00:04:49 -0400 Subject: [PATCH 48/61] Set the alert default button using the CPCarriageReturnCharacter key equivalent to match the recent Cappuccino change for default buttons. --- AppKit/CPAlert.j | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 500d46365..9f935f145 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -301,9 +301,11 @@ var CPAlertWarningImage, [[_alertPanel contentView] addSubview:button]; if (_buttonCount == 0) - [_alertPanel setDefaultButton:button]; + [button setKeyEquivalent:CPCarriageReturnCharacter]; else if ([title lowercaseString] === "cancel") [button setKeyEquivalent:CPEscapeFunctionKey]; + else + [button setKeyEquivalent:nil]; _buttonCount++; [_buttons addObject:button]; From 32fb13a9a9a6f8b5bb84e537a3a7caef2f5550a7 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Fri, 18 Jun 2010 00:27:28 -0400 Subject: [PATCH 49/61] Fixed: long titles in CPAlert buttons would be cut off. Fix is to use the standard 80 pixels width as a minimum width only. --- AppKit/CPAlert.j | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/AppKit/CPAlert.j b/AppKit/CPAlert.j index 9f935f145..9f04ec545 100644 --- a/AppKit/CPAlert.j +++ b/AppKit/CPAlert.j @@ -145,14 +145,13 @@ var CPAlertWarningImage, for(var i=0; i < count; i++) { var button = _buttons[i]; - - [button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)]; - [button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]]; [[_alertPanel contentView] addSubview:button]; } - + + [self _layoutButtons]; + if (!_messageLabel) { _messageLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; @@ -161,6 +160,7 @@ var CPAlertWarningImage, [_messageLabel setAlignment:CPJustifiedTextAlignment]; [_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; + _alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)]; _informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; @@ -288,8 +288,8 @@ var CPAlertWarningImage, - (void)addButtonWithTitle:(CPString)title { var bounds = [[_alertPanel contentView] bounds], - button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)]; - + button = [[CPButton alloc] initWithFrame:CGRectMakeZero()]; + [button setTitle:title]; [button setTarget:self]; [button setTag:_buttonCount]; @@ -309,6 +309,27 @@ var CPAlertWarningImage, _buttonCount++; [_buttons addObject:button]; + + [self _layoutButtons]; +} + +- (void)_layoutButtons +{ + var bounds = [[_alertPanel contentView] bounds], + count = [_buttons count], + offsetX = CGRectGetWidth(bounds), + offsetY = CGRectGetHeight(bounds) - 34.0; + for(var i=0; i < count; i++) + { + var button = _buttons[i]; + + [button sizeToFit]; + var buttonBounds = [button bounds], + width = MAX(80.0, CGRectGetWidth(buttonBounds)), + height = CGRectGetHeight(buttonBounds); + offsetX -= (width + 10); + [button setFrame:CGRectMake(offsetX, offsetY, width, height)]; + } } - (void)_layoutMessage From 8f040d6ff1d159429bf61d6c8acddb1d0359bb0e Mon Sep 17 00:00:00 2001 From: nciagra Date: Mon, 21 Jun 2010 13:53:17 -0400 Subject: [PATCH 50/61] Fixed a couple of Unix key bindings. --- AppKit/CPKeyBinding.j | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppKit/CPKeyBinding.j b/AppKit/CPKeyBinding.j index 77cdde0df..5cc46b422 100644 --- a/AppKit/CPKeyBinding.j +++ b/AppKit/CPKeyBinding.j @@ -30,6 +30,7 @@ CPStandardKeyBindings = { @"^$a": @"moveToBeginningOfParagraphAndModifySelection:", @"^b": @"moveBackward:", @"^$b": @"moveBackwardAndModifySelection:", + @"^~b": @"moveWordBackward:", @"^~$b": @"moveWordBackwardAndModifySelection:", @"^d": @"deleteForward:", @"^e": @"moveToEndOfParagraph:", @@ -48,7 +49,7 @@ CPStandardKeyBindings = { @"^$p": @"moveUpAndModifySelection:", @"^t": @"transpose:", @"^v": @"pageDown:", - @"^v": @"pageDownAndModifySelection:", + @"^$v": @"pageDownAndModifySelection:", @"^y": @"yank:" }; From f81e97726a2f08416e90e5694e65d2d9d52ab0cd Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Tue, 2 Mar 2010 11:58:44 -0800 Subject: [PATCH 51/61] Fixed setName: in CPImage to return BOOL as in Cocoa --- AppKit/CPImage.j | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/AppKit/CPImage.j b/AppKit/CPImage.j index 0bc69ba60..53a3f1937 100644 --- a/AppKit/CPImage.j +++ b/AppKit/CPImage.j @@ -193,6 +193,9 @@ function CPAppKitImage(aFilename, aSize) var imageOrSize = AppKitImageForNames[aName]; + if (!imageOrSize) + return nil; + if (!imageOrSize.isa) { imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize); @@ -205,17 +208,19 @@ function CPAppKitImage(aFilename, aSize) return imageOrSize; } -- (void)setName:(CPString)aName +- (BOOL)setName:(CPString)aName { if (_name === aName) - return; + return YES; - if (imagesForNames[aName] === self) - imagesForNames[aName] = nil; + if (imagesForNames[aName]) + return NO; _name = aName; imagesForNames[aName] = self; + + return YES; } - (CPString)name From 10c067e44f133c29aa8990d11fa3559b3e32f0e5 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Mon, 21 Jun 2010 22:32:18 -0500 Subject: [PATCH 52/61] When dragging over a tableview row we should jump to the next row at the bottom 30% of the row, not 50%... otherwise it gets really really bad with large row heights. --- AppKit/CPTableView.j | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index f67079a90..23127b643 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -3070,15 +3070,16 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; { // We don't use rowAtPoint here because the drag indicator can appear below the last row // and rowAtPoint doesn't return rows that are larger than numberOfRows - var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )); - + // FIX ME: this is going to break when we implement variable row heights... + var row = FLOOR(dragPoint.y / ( _rowHeight + _intercellSpacing.height )), // Determine if the mouse is currently closer to this row or the row below it - var lowerRow = row + 1, + lowerRow = row + 1, rect = [self rectOfRow:row], - lowerRect = [self rectOfRow:lowerRow]; + bottomPoint = CGRectGetMaxY(rect), + bottomThirty = bottomPoint - ((bottomPoint - CGRectGetMinY(rect)) * 0.3); - if (ABS(CPRectGetMinY(lowerRect) - dragPoint.y) < ABS(dragPoint.y - CPRectGetMinY(rect))) - row = lowerRow; + if (dragPoint.y > MAX(bottomThirty, bottomPoint - 6)) + row = lowerRow; if (row >= [self numberOfRows]) row = [self numberOfRows]; From 7e25166ce162505489cfe4775498f0291aeb6bf4 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 23 Jun 2010 19:13:24 -0700 Subject: [PATCH 53/61] Revert the fixed frame size assumption for now. --- Tools/nib2cib/NSButton.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/nib2cib/NSButton.j b/Tools/nib2cib/NSButton.j index 6bbb426c0..a9adfb9c1 100644 --- a/Tools/nib2cib/NSButton.j +++ b/Tools/nib2cib/NSButton.j @@ -93,7 +93,7 @@ _CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20; _bezelStyle = CPHUDBezelStyle; } - if ([cell isBordered] && _frame.size.height === 32.0) + if ([cell isBordered]) { CPLog.info("Adjusting CPButton height from " +_frame.size.height+ " / " + _bounds.size.height+" to " + 24); _frame.size.height = 24.0; From 7c5a07f709ec9df8b963b49383ba32f9a3a58767 Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Wed, 23 Jun 2010 19:58:43 -0700 Subject: [PATCH 54/61] Fix the issue where CPSecureTextField would sometimes cause all other text fields to go crazy afterwards. --- AppKit/CPTextField.j | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/AppKit/CPTextField.j b/AppKit/CPTextField.j index d3873e524..6440017d5 100644 --- a/AppKit/CPTextField.j +++ b/AppKit/CPTextField.j @@ -807,11 +807,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder"); { if ([[self window] firstResponder] === self) window.setTimeout(function() { element.select(); }, 0); - else - { - [[self window] makeFirstResponder:self]; + else if ([self window] !== nil && [[self window] makeFirstResponder:self]) window.setTimeout(function() {[self selectText:sender];}, 0); - } } #endif } From a6b7d456f43f22e0fe737c0b59803c45eebc486a Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 21 Jun 2010 15:12:45 +0200 Subject: [PATCH 55/61] Add isLoaded to CFBundle and CPBundle --- Foundation/CPBundle.j | 12 ++++++++++-- Objective-J/CFBundle.js | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index 39aae0b29..89c082c4b 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -118,6 +118,16 @@ var CPBundlesForURLStrings = { }; return className ? CPClassFromString(className) : Nil; } +- (CPString)bundleIdentifier +{ + return [self objectForInfoDictionaryKey:@"CPBundleIdentifier"]; +} + +- (BOOL)isLoaded +{ + return _bundle.isLoaded(); +} + - (CPString)pathForResource:(CPString)aFilename { return _bundle.pathForResource(aFilename); @@ -133,8 +143,6 @@ var CPBundlesForURLStrings = { }; return _bundle.valueForInfoDictionaryKey(aKey); } -// - - (void)loadWithDelegate:(id)aDelegate { _delegate = aDelegate; diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index 8c7044e73..03639c8b0 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -235,6 +235,11 @@ CFBundle.prototype.isLoading = function() return this._loadStatus & CFBundleLoading; } +CFBundle.prototype.isLoaded = function() +{ + return this._loadStatus & CFBundleLoaded; +} + DISPLAY_NAME(CFBundle.prototype.isLoading); CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) From 07630964c14e4366331b7eed0206a7dc8cdb3202 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:03:17 -0400 Subject: [PATCH 56/61] Reverse bindings support for CPCollectionView selectionIndexes. This enables binding a CPCollectionView's selectionIndexes to a CPArrayController. --- AppKit/CPCollectionView.j | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 084686395..29e875ad1 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -312,6 +312,8 @@ while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) [_items[index] setSelected:YES]; + [[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"]; + if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) [_delegate collectionViewDidChangeSelection:self]; } @@ -873,7 +875,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); - + _maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0; _maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0; @@ -905,7 +907,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", [aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey]; [aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey]; - + [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; From 6b55c814627e5341beffa31558b3df79f0748ef1 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:17:35 -0400 Subject: [PATCH 57/61] Fixed: Shift + Arrow Keys in allowsMultipleSelection CPCollectionViews did not expand the selection anymore after the recent key binding updates. --- AppKit/CPCollectionView.j | 56 +++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 29e875ad1..2a7acb44e 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -739,9 +739,10 @@ @end @implementation CPCollectionView (KeyboardInteraction) -- (CPIndexSet)_selectionForEvent:(CPEvent)anEvent withNewIndex:(int)anIndex direction:(int)aDirection + +- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand { - if (_allowsMultipleSelection && [anEvent modifierFlags] & CPShiftKeyMask) + if (_allowsMultipleSelection && shouldExpand) { var indexes = [_selectionIndexes copy], bottomAnchor = [indexes firstIndex], @@ -756,7 +757,8 @@ else indexes = [CPIndexSet indexSetWithIndex:anIndex]; - return indexes; + [self setSelectionIndexes:indexes]; + [self _scrollToSelection]; } - (void)_scrollToSelection @@ -775,24 +777,46 @@ index = MAX(index - 1, 0); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; +} + +- (void)moveLeftAndModifySelection:(id)sender +{ + var index = [[self selectionIndexes] firstIndex]; + if (index === CPNotFound) + index = [[self items] count]; + + index = MAX(index - 1, 0); + + [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; } - (void)moveRight:(id)sender { var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; +} + +- (void)moveRightAndModifySelection:(id)sender +{ + var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); + + [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; } - (void)moveDown:(id)sender { var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; +} + +- (void)moveDownAndModifySelection:(id)sender +{ + var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); + + [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; } - (void)moveUp:(id)sender @@ -803,8 +827,18 @@ index = MAX(0, index - [self numberOfColumns]); - [self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]]; - [self _scrollToSelection]; + [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; +} + +- (void)moveUpAndModifySelection:(id)sender +{ + var index = [[self selectionIndexes] firstIndex]; + if (index == CPNotFound) + index = [[self items] count]; + + index = MAX(0, index - [self numberOfColumns]); + + [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; } - (void)deleteBackward:(id)sender From 2da1dc31fb4c78cbd8f866cbd938b698ed6f9170 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:28:55 -0400 Subject: [PATCH 58/61] Simplify CPCollectionView keyboard selection code, eliminate some redundancy. --- AppKit/CPCollectionView.j | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/AppKit/CPCollectionView.j b/AppKit/CPCollectionView.j index 2a7acb44e..93022f119 100644 --- a/AppKit/CPCollectionView.j +++ b/AppKit/CPCollectionView.j @@ -742,6 +742,8 @@ - (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand { + anIndex = MIN(MAX(anIndex, 0), [[self items] count]-1); + if (_allowsMultipleSelection && shouldExpand) { var indexes = [_selectionIndexes copy], @@ -775,9 +777,7 @@ if (index === CPNotFound) index = [[self items] count]; - index = MAX(index - 1, 0); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; + [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO]; } - (void)moveLeftAndModifySelection:(id)sender @@ -786,37 +786,27 @@ if (index === CPNotFound) index = [[self items] count]; - index = MAX(index - 1, 0); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; + [self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES]; } - (void)moveRight:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO]; } - (void)moveRightAndModifySelection:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES]; } - (void)moveDown:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:NO]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO]; } - (void)moveDownAndModifySelection:(id)sender { - var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1); - - [self _modifySelectionWithNewIndex:index direction:1 expand:YES]; + [self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES]; } - (void)moveUp:(id)sender @@ -825,9 +815,7 @@ if (index == CPNotFound) index = [[self items] count]; - index = MAX(0, index - [self numberOfColumns]); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:NO]; + [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO]; } - (void)moveUpAndModifySelection:(id)sender @@ -836,9 +824,7 @@ if (index == CPNotFound) index = [[self items] count]; - index = MAX(0, index - [self numberOfColumns]); - - [self _modifySelectionWithNewIndex:index direction:-1 expand:YES]; + [self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES]; } - (void)deleteBackward:(id)sender From 74af0dc93a35a3b10bd84e2cbe3743e625c52bec Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 26 Jun 2010 00:56:35 -0400 Subject: [PATCH 59/61] Fixed: Shift + Arrow Keys in allowsMultipleSelection CPTableViews did not expand the selection anymore after the recent key binding updates. --- AppKit/CPTableView.j | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/AppKit/CPTableView.j b/AppKit/CPTableView.j index 23127b643..480c01373 100644 --- a/AppKit/CPTableView.j +++ b/AppKit/CPTableView.j @@ -3360,6 +3360,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self scrollRowToVisible:i]; } +- (void)moveDownAndModifySelection:(id)sender +{ + [self moveDown:sender]; +} + - (void)moveUp:(id)sender { if (_implementedDelegateMethods & CPTableViewDelegate_selectionShouldChangeInTableView_ && @@ -3407,6 +3412,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5; [self scrollRowToVisible:i]; } +- (void)moveUpAndModifySelection:(id)sender +{ + [self moveUp:sender]; +} + - (void)deleteBackward:(id)sender { if([_delegate respondsToSelector: @selector(tableViewDeleteKeyPressed:)]) From cdb1ac32fab318dbff1561704533832404503307 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sat, 26 Jun 2010 23:17:30 -0500 Subject: [PATCH 60/61] Use the new Aristo HUD window art. --- AppKit/CPWindow/_CPHUDWindowView.j | 22 +++++++++--------- .../CPWindow/HUD/CPWindowHUDBackground0.png | Bin 311 -> 1141 bytes .../CPWindow/HUD/CPWindowHUDBackground1.png | Bin 179 -> 1033 bytes .../CPWindow/HUD/CPWindowHUDBackground2.png | Bin 331 -> 1166 bytes .../CPWindow/HUD/CPWindowHUDBackground3.png | Bin 114 -> 1002 bytes .../CPWindow/HUD/CPWindowHUDBackground4.png | Bin 118 -> 997 bytes .../CPWindow/HUD/CPWindowHUDBackground5.png | Bin 114 -> 1002 bytes .../CPWindow/HUD/CPWindowHUDBackground6.png | Bin 182 -> 1017 bytes .../CPWindow/HUD/CPWindowHUDBackground7.png | Bin 115 -> 1000 bytes .../CPWindow/HUD/CPWindowHUDBackground8.png | Bin 185 -> 1019 bytes AppKit/Resources/HUDTheme/WindowClose.png | Bin 349 -> 1580 bytes .../Resources/HUDTheme/WindowCloseActive.png | Bin 663 -> 1765 bytes 12 files changed, 11 insertions(+), 11 deletions(-) diff --git a/AppKit/CPWindow/_CPHUDWindowView.j b/AppKit/CPWindow/_CPHUDWindowView.j index ad0efd630..ab9c283b4 100644 --- a/AppKit/CPWindow/_CPHUDWindowView.j +++ b/AppKit/CPWindow/_CPHUDWindowView.j @@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0; _CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: [ - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)], - [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)] + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)], + [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)] ]]]; - _CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)]; - _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)]; + _CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)]; + _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)]; } + (CGRect)contentRectForFrameRect:(CGRect)aFrameRect diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground0.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground0.png index f43a3aad245ef5ce1ba726bcdeca66d9c5ffefe9..49f0f1bbf2edb98e4ab1b57402d809f8e47c132f 100644 GIT binary patch literal 1141 zcmbVMJ#5oT959l~zlCs1|XPW`s#LT%T!kT=$NKZ(1Xmf*Kxjyd3}GpBWxFc8=elDZ!Fo zz{Ae&i2(Oc^j55i5lgZ89os>7LuCXmrY2~(qh6>sa{N56%FfZXz=L@R9m(-cr>dns zP#^&YnIueDP=Y{0Nt8;5v5ll4@R1VaK+6eZ#i#RNkn!f}t9jf5A*TMRl5t-$fALp%^Mnl&;;b3F638G`GV zN{hr^xR5B8GNEDm0!l)`b)&fE(IGA4A8ss(4lCn67RopzV}Zr$F&J+tv)ujKPy}S& zsQUtk6~!FYi8bb8j~4YD&%PvW$5tWALWJZrltn0I5mFFTbls2)O*2xGF19$9(#;z% zlNYm^tmH+6bVEsNNVUpsLPBi-R-EY8_yGY&FbpSvPz4?z^t8uC^6zZBL&*dvvsi__E7Z~s0tv*FnFx%h$D#foWJR{Il%*mW+p_Y*5Vy0-Ti*ExA_^7z}6 z4{DDeF28W~-0K;}@oIAR&B1@qx82EKxiMLM0=}+`Y4CPlMv!+tu=X`ORcp)APa}LvMdjrbLO0bx~}gCR7FwjaI9$>|Kdg9 zVvLbp*LeV7F|b!k@wRPQTnGr{aPIpaK7rAC0>~Zn{|08Mf;ihm+Vq#m+s5LZ7)}w2lorHWJq;;>2RE6S-Ay*3YsqGscEPP>yXYP_n@qc*O(rH&H|?cj zPyPS}51u>;;veXt1@+)b&w}7d6oekUcb)7<^-y{+kjzKk=Xu`Gr|WAgb2B$)BuSd9 zuac%%r^I{n>a_SC-a33OmU+J1<{NC2_uYg_me0Br)I)cRHmU3HJ^V-)CF#m$&}#E` z_;8*1b1iN9$!i8Iy`r>flJJT_Ie-|s8^qQa6b6&Z$+ zb6{K$7KL;#;%-)m(uD~Fp{bVyF%MV-az?kyc6n76o{mBY<3{70I7-Kf5-C$NH&&4X z)iBKC8d|5kN&mWWp>^8Yi>cbADcemvQIE}q30UOra-rN%cw^p60#OuqhcIt9q!F)^ zsx1B}e&CxBRUkro3F;VX6@&}~4MH5vu`H*k5j^3z2wQVtxrQstx>3Uj5yvQ5hOHHK zfi9Qzk}<*7qm;XmM<=?0&>dsRrC8HWsLNT>Vr*y90qZ@+S=wVUus2Ge;d()opY!sJ zq9rs59#P*(SO|vsHG>QEbq(8Ajo_j+io4=yxKhGa*~X5@hVXra_5UYls&Gclo8zBm znOunu%(v&QFAnF!LnARUi5QLNKd${2V`bEd)ylqfJDpDD-M7=z!ONdtkNO8M&IW@| ykBLO*KYuuRe|#`F^PZiwR^D9y_1#UUR%gM9G(Ai2+u188AI|#n8hKmmJoy7`NJmxx delta 128 zcmV-`0Du392(tl@7Ya@Y1^@s6;TwD~ks&8*098puK~xyig^xiFfItWX8;*XFr*rZj z(t21EUBvZ52va6t0Csct%_8D3Nf-qHjHE_aKxU!^lJuBO04*SSt#!HInP$r?vKHJo i7fUDT{#~m+A{CsAhnRl26vEgXx0<5pknW`l4*^VRUbU(Ye72e!vjM7>wz3Ohv@GO?;3s7(40htv(bV7D&$d zpY#9y{@?jvpnu=m)!SB66t%Y4r4vK9AM@t{9~8)k?o)%J%G zU3AS+R7R#fIer!OP}K4fr&7h$(i^hnyR4b$u(2BuG)48~nhb*7Csj%7eZuW zKdkuvSgQjDYCiU(njg@G!3?~nl6!?Ow>3mvk z#+@?+K9}LuY=JjOHi+*{to?s-#t~<@q&c2xmevvJz+}7F`b1b99^{dU3CU<&nav+2 zWA$}WS1a+)U+v$s?px3?@!4zI`aPRp?>HEKbo2b>U%NV9TD8NtG=th+F1~%__jBw} zXS*7o-t@Qf-mtQQ+7;ivG=4X?;rjz^Lqk6v-T2qd{Ort{(hoPTfALGY(S0VGt9;zK z#li=sUwol{jq5(R;dV~D^`ujy>JO(MJkXA<=&N7+t+9FIvh|zt^<%kDPS)<7_%s(C zI{xlmLh%}Z5P?`2tjh{!jP14!Gp`)Qgi&+}DX*KZ=S1=gaf z48veu*C{|z6tBRim>DzszSk_ve^x*xco@f#G))s=BdTgMopY8X34okT_&Cv+dHvzy zD(4(NZ%;%Nw=<|}pvE;<7CT3{tBc~Qicf#lIe1!*5Dj~R#^04Z*6!kV@16*6_jn(1 zT`k`3f+a@0kK4(^?<4%{3$OigyZ;Ipu`2+60aGi`mgR_+F8}}l07*qo1w^hwV1gB> Bf7k#3 diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground3.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground3.png index a38e4dad1b09bac67f1faf1737e41fe30e206010..3ba64c8226c960400416d364bc0e848ec22b0a3b 100644 GIT binary patch literal 1002 zcmbVLyKd7^7&by&ROkR3osQg<_+0GRu~kz!c1+v|(&n}m9Vx^ zsx%j9N!r+~@-RA}9E|8B$!z)j)0qsC*p{EQ0~F*gohI9-1>HN{8APWCkr~UIkHAJ{ z34)aJ5LD@5R$7%U&v`AeudksD<|h2WmKRP9gI(aVf`Yb!S`pF_(6NG5%`l9IfFO(@ zA`p`nHY}A`2!Z7z3$-F1TYb-8YKfCAPdU#m2xqgIGE)^+OdvK*v*sYAB`jLyNyfvf zm6huagGbA#NOGRA4AhL_h#hlV7M?CbNb?}LAkNBVqD0DI73L5t2&QQr*W9|~efrmp zORdYnNlsy(mh8BQL_Nmq4OryvYN6Utcw;>+5>b@!&|}eYN;BT`Y+3wK;v}{Z?jVc} z4H*RK9gIzkOwaRm-*J3Z_ejHW8MfU1G_VSj#PF$XPL9?6B#8-6`X&oU$Cadm0GBD9P$`U7kg>9xamRH1-RYf_Z+e zDC$7`=i0Ulj?)WaI1^*F*7KY}^e delta 83 zcmaFGUZmI=;OEZECB?2 diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground4.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground4.png index 4d450f53a76b047a87705e372f020e39f090d512..eb0bc87f35a18f8dd137702011fd0b8667551976 100644 GIT binary patch literal 997 zcmbVLJ#W)M7&ZkVR8a{bF~HK3%Si0Ii(|)DP38D%8mTT(8broA_NB2}`^@=D+>UIl z6~BX#g@J{IjhWwo#LmPyi3>y30ZaCM_Tpo+vu{dN?F^@P^yo60C=x5O}9nvT{fAfuQE6VL@IvR^{xbMU))1ul&tFl6( z6=i#;Dx&y=3NWF^Y3{1OK7Ua`nz-ugP6)%or?YhLg44r`gHe2O65ENo^BinfjwHya zh(MK{=A~1)>Vnsi`}$f}!NNqGxa!iWaX0`z;}mo>*ovVEfr&KKHZ03}1~5cWhge6r zg)FCy9SFhdQKcGBrp}NAD=m3))tL~5qwDkeT${Hw#*cMm+jh-?aZ6gX%JW=ARVy#I z8U{kkn5TtESq^H(Xu{5ft4dFoA!J1uUJ>WzDp4|JdKDEq(x9GYbzBSUQVi)|H?FlV zN9P6AhqPp8JeKvCZZ%+;yPJh-L+Oq4lBcpL(J5i^Sw?fwC$1|0Xi1tl5OpC!mH{mc z%`QSVf;J(68F*gMHVJMxuEX{M1dT4TEW3vhB7tpqwr{pAiSBeP!)~zsycAI$(?&Oy zx+|=CBi8XbjRfN(#!j0K7|fVp<%|`;KQurX#c5uj>+&q4C6uRcX%cXjfkl3u^csE3 z#J<-fxa}?D?gl3A8rbXjIFQ+pzAv%K|Kv=U&ggY>{L?JWmF&QJd)4~#a5X$MmlMO~ yXv|)%K{-~B`otSmKPDe8FMoek?(E+mC=ZU5hr?Us`)227J$U`y1M;zV^zIK&Y%InA delta 87 zcmaFLUZ&U?;OEZECB?{kU`Gs`lejQc9k68Ihu`OU-p@Dtok#0y8*73fthe`^E?;l* zcjeY9|K7R%;hZmb*>0a5&>@@n84;|I4hU$+{t@XCKb$`QMz#du+A!+%S>JnX1T>cX z(nc!cl%oYX%7L0 z2+9!42-lEi)Ug2}SUw_G%fg}2b=;*EKbhi)vDA>|$z&o;>JrV4WTfkQ$$@c=Th#Jt z!u+C^o-kA7o-RU&Q_s5~PV!}oMG{z&v+X3zdf48{Y0Z^z_%)SF8QQ!?*XhUl#Yk7vVwY`uX_xjk9w4 M+PfX+ee2olKk&3NQvd(} delta 83 zcmaFGUZmI=;OEZECB?>(57A*h( diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground6.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground6.png index a2cebe44fd81c03b9e001e7b37b39fbe7b932a1c..01fe3ad8ad7fb74ab4e4bbcf8a92a1a501823a6e 100644 GIT binary patch literal 1017 zcmbVLJ#W)M7RWd*@$Cb605b(*jM6qs@RbD z0}T8HC^JJP5CaoCf1)EoES%H0AW?O|l6@b3pXYf$U+ru^T3WcXAW71ayGc4?y(!-7 zx8}w7+2`9|#InrWJ-*9^eBx(RYKCk;fgAfH+M#}U`1~tf6M$jV?eU(sWd$r&{L)4# z;#8m|X>Gko{a}xBFrcF-vE{Rmr!t5_TYlQ`ke9aTINChQ=;zc@1SSHQ{@QP5COEkGIq8dh+9RoC_VKt&iq zq(ZFLux`~=3n4IjWTBRYL#soanU*-&@|g3~f^agKD3iLvvJu3lX_g$SS`!wv{4n8u zQA_fbihKVS#kmW8M1A;hWYT@WYvEKwq5u<%oe6$InBjB9G0^A7#v z#--MI_b{cfLvwbJ1)?6ql?p6!cePMyD7>*AXOSq1zfV|j5YvRa#FoV$C5%D~VFO{T zuOeMVnt`#2kx7W7InAb1*N9qiT!wY9)>t(fs&2M0#>6qrw%I0a4XKW1I9k2Jx=GIc zB%qaUBy?w3d?nUuWz^>^>oT@qb->P;ah8u+3R=4j;Q2w6l;^TM=g|_HMK5URWGn{L z{94f^`v1he(a?#5v7wQcX4Fl2h7JEGXHYl;%jWp2S*k11f#vq1^~K?0cxWOfCKIFK ze*1JyjMY7tG`q$3LD=sbD-gc_`Rm8o>EihK#@5LR!u`3|;O(LzJv^S1K0KMf`)1h- O%VBie+vMFw|K)F5YBq)d delta 152 zcmey#zKv0_Gr-TCmrII^fq{Y7)59eQNV9=32Z(%d=Do*6MfE&}2u~Ns5RT~NgoK10 z>({UU-!pOIN5u)fJ(7GYSFN&p`s`Ufe?3zZxrAi}_5y!qHR%@TJuf*+GCN|Wa zfq|8Yje(^L6)Ou8zk!K`iPuS77^)6fvhTz1^E~h8>z(b#t1I_bBuQHBZMl6|ufTil z<_-Avf3Ra%?uyN!*yUp}3vwpe5g#$sOM(gOvmiQr@rA7eU>pyIV(33HL!Kx>Wuufy z253oI-zc*n++zZb*d$IZ`RAw4GKwQhe%AJ}pE+zAZyn`q_h@?%9_@ujByT)I>!k?< z2@?S-ll`fny{~~RT<4q#GWNDoErK&$l*CdZ3Q<%tYM@Pg*02bu0KQ+6RcvY z651fT*`y}MX!*#XmPcc=?|MruI9c*kh|E;g*=(lFnhMV+DlrVB;-Itv7LDRC6+ziZ zi?y1;Wks0BnTUCcD#l>M4}>Lyr;8Ah%=gcU(_)z@NSRs&nMxF_CP@|7+`15b_ScOI zt&727#?(G5_(2{*J;rM_7;<;HP-O_-m{0QEtXBJRfkrUw6RHlnY)=d4`(_X~g@if|LQM>I>53&KiFR;=7})shliyw zF*%IJ`**MI!&u$vx%Qy^K6-O<^857k?Ck8TbbTUSy(QiLcJ;yAkL_R8?DaOc-4EU8 G$A17OUNVOO delta 63 zcmaFCUOYjZi;aVgfq{WZ;EUlzMRjckQBN1g5RT~NgoK2O6Af+>5)wAdn;E>{vfgRB S+j11BlEKr}&t;ucLK6TGvl4Rv diff --git a/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground8.png b/AppKit/Resources/CPWindow/HUD/CPWindowHUDBackground8.png index 60e25e8e0b844ac30a4c926926d4e1757e139e7e..14c5c58e13194640bb2a1d4f11b49882b870cd53 100644 GIT binary patch literal 1019 zcmbVLJ#W)M7&f4ms!~S=SU9;O#J+QCJGSb!X)dObaH-Nrq%3f;FOAjOXY31cs}6_( ziI1s5LJa%`{s2P<%D~8m_yhZ*JdS2nrp4$ zwpcHV_tMO?_}>3;<)c`x@@AKBvOXV?luGr0^(bgXWSh1r3HBa-qKg914?A7n^={if zixg7WD0!3!v?MJq=Lzw5CK^ox1|5WJ`zhVrU+?()JH8dj z%S&J}w*^5&IRSaJ8)tUz$YWkx?2Btv24fSxB}v-y$%)67r9goi8!1taOPA$Mfq=}8Dt;(4dUaW+YmNST_GL`4czqo{~$ zY@P8o{o}@&)>&sSp=z6EY?%6@9{u?eEOK|gP+=&%vG1gzC<@ud%pXQH<}K{V;*S!9 zfeld&B4jQ=Q-ekgAqznZW7lx&b+>9@t>ich>moy6sOg4jH4sABwXCMq#7zTgu2FN1 zYKd*d87Hw%OWjcDPO$p9Si6x@!dcp3Y`5%yjRE5<8?Xd4Hg(_;Ka7iWQJ#}%F-^lq zG;mWEfpLEA@C^Nb;$GEF>>^Y%aKoroEqQ_s{wHUua7HbfA4aKK!MnrSlnYmP<@f-LZ40{K{3U>{vJPFZA&6_O=%k6|Ln-xo&hIq>1I~)vNQ3 zjEv^7bQKy%NJ!W)XR@zs;nFg8U_3E{IpD2~fg{7R4YK}h)1$(H_Az+6`njxgN@xNA Dmr*ZH diff --git a/AppKit/Resources/HUDTheme/WindowClose.png b/AppKit/Resources/HUDTheme/WindowClose.png index 4d3d405cf12637145838d0611dbf8007b986f43c..17ba6f603e5b46abcf9b132e5afcd40e826f3a1f 100644 GIT binary patch literal 1580 zcmbVMdr;GM91n`3ptqa23ApWI^f+HMNegKcTO2f$$1Gy0$cfB_G^H6dDQSdK5fpKQ zI@yU%^c?PV*qbtRoD7)SiQ~jE#kaDROjy4}t54|A9NUf<8>^L_nN zk&+xgJ}@j00D$p{38X<9CwSj6qor@!iONON5Gux{i>bU>ET9Aih%xb5447!8vKa$I znF{kd7&QQlG_%HZF9XJGmtVshc ziqa!`o0hS#2~L4YbtW5WXAX^ihc%b86AleD#7jtX?=}p9LndO5 z272mLx;_Qe@&W@!$&d&d!4MEbWvC)jsZ`Dev;evt!S%E^v3)wJ=19@i6B9`dB%R1itcgHS6@sG5NJJ?| zFcpg8D1wuu4%5ZN=oA9!JJuh+K!MbeO`2P2}t% z#nFsUmz8vfvB(RtgjQfEkr#|SpX=*@6bmo%b_;IR&8C2wIj0g+{OOyzkyym?v_1j zxwY-%TbjP*cRjA%yZ4vm&3LkK`ozHcuG{w?p8aKD=8xM?S|W@6`bMm3UAwp*Q|lA* zh?<__L!W)xX)bykSe$U&9~(D%^$GJnO-}R0h3dMJV8aqwmwwtCZP9+2zm0#iaWG63 z)O+P%TaTmiCs(+;%XszPU|RDn{hiFZW#XkPww|cg>rAnkI66 z{1v~J%=)zRSq+0{vKo3f7&)Lt;OO?S5U*c=PeZfr7&e_pzi-*>D3 zucPx?V;4NQeta_>wob=gD6MFU8tGOX^}qpYf*_n{ap#q~Y9&+mP3 z^4+~kdC0ikr!501Wr*r17QSeu=2Vk=^y-*BZlI|yrS|;$p5*Wi^T%2rOv}EPH2C-9 zx48cEyJ}`sADfe)UU_@MWI*}0zkgZzV1B4_YiGckSgQK#wVCX-fXQ3t-3+Vxqjl8b zQBD3`t`fK=d1-v78!OhAf9bbeRvq-P=-XL_mX7{l%Yl$%=6%$4qLC|}boKDoR{W#x z>ZG0DHKg~-UCokm$hFd{I?Mf%qQ>8oHt!7DS40!|m4<^59qMv+KS_W~+dt{clN~vG gqc&~N(h=i;ulBwZR7gy{>HU8v#wC+`V&5zM2gFWZB>(^b delta 321 zcmV-H0lxmM4BY}DiBL{Q4GJ0x0000DNk~Le0000K0000K2nGNE0F8+q4Ur)ye*phU zL_t(I%gvOr5rZ%cMJZT;2^fU|($cdMC6ya5#RTt<7u-Aka=e{3lfr=qsWE3)fPHH8rvU7Xx{h+WPoDb|21&=-%C zA@19s>4CKd+<>-hBM&Xx1ZaWnw8G-rPYSJ-*2^`NRIMQpPrb5(l TxlyW$00000NkvXXu0mjfQiqZB diff --git a/AppKit/Resources/HUDTheme/WindowCloseActive.png b/AppKit/Resources/HUDTheme/WindowCloseActive.png index f4228235806c3e79259c5bb45be04d142b25ac31..5fa29fed3c88a7401d9ebcce7f9c7da3d54a77ae 100644 GIT binary patch literal 1765 zcmbVNeM}Q)7;i)fkX2?^21C(XA$&O6-nG!L!5H-D=%Cn@3W$P~_OPY2SKFf$2o6{f zQBaV{aDoVms7yp>`P_m;bf6;Q#uN<6CJTrkU;@a8Q+7pgOJ?@RF1dT(=e_6md%o`q z#1Wqn?Op5%1OibQ3QO>nWVvl^@MqMm1JU^M0TvR2MWRVqnoN%nf)r>X0thv-ornaH zDbjcKApQh`Rgy{?gT;u#d2&=klUa0VCXEh96A1o+CY?;KMlc`|*{RY7P$t_uD1b^4 zK#BGffg&9rQK~{S^hjhzgjAlPmU9)9z)t{w6AvfQAeam=X;QQXo+*H`#LL6?mSZ{v zSW>~%0hHHH#fZcJAJrp(9}T3+K^6$GAR5H?|y3@XItF&R7%1ePxf zZcVR9;z?k^vMpQ+peQj+$D`BJ($Z*YOd6`+Nr$*xu7!iapyC=-L%J4|nW$QW+X@4W z8031D4pX68z``g?L{qT<3hwFa5HvcG=nb*fu$(A7WptBFM~7%2U8AwYwWMvpB*@=x zyj9yEP1hlG31UD~^>Vx(Np34(Ja_+X$fAgQ!`rM^;YE?9z^FV`gJ>}!96-U}&=e{K z4}>@%1hIWVHUngFAczZrTo@Lx1VKRpCJSb)aJ&u6V6$Kr$l|iOd?p0J0xma%8v=*0 zK!$+D5wMsmSfSQ{$+U80#jXmsyNu=hCzi+8BQgxtOHnjsr31uD6hjS4R0r@Q{Q!|n zuF_g$OL<;L3nO}!5m5;As0LWdFHiLr`~QkN*pCehAc(_)`792TOIgM${!h;6xHEK1 zbNr)OR*vuvv~1tBJ}$f&9z=^zj2<72443&CeBvC1aFEnA^qn*;Y@Li;86EH8;o%N7 z9a?=!BqUe2l-Ae=#|@A!7H={>mXAe6x21X-w-w*XGe)*`e?IQe2(X-0ROpoZFTRsP zM$gTYW7orPH@MD?9&J6}I$JSCyg!bW=eKZ1b7(o*y1KfBkHgez^$jD2ku~Pn5@Y*Q z&-~7W&~-)Ex~8Y6>w0^8UBX>8kX$Z*C+vhOFJ}K$N>}2Av2kpH+BdbHq+b7%x%wJ>3vR=m3N`%L% zs=hpxt>gS@ztQgLlP5kq;^U2tKRCa1N|*~Ree7yi<7HD3F;>(!R-f*_!E8Xo8^&X{X_A1tf;a`jS+%6x-+x!0L-qRqR zd+gl0`WaH0{-ay*l>(*tfV*|V-4ZdfwW&VJzg}VWknCoc3tWl1Yrf~`Zr$l!9rIqM z8>yhH_?aySQT8(jyX&roCYUoe7oW6FDA`;qDRdXkBwp}Jy!mPC_E)=%#`o*8`}_O9 zS(86vH&5WZa<=B@=P#0Or)_0!*tjt;J}xfHevEi}GAAILcFxMmifB(5E=x9VT9r$F zh`N*P`X(kO`i>kqqF%LaGW1w^xfhK_D|2vgDDo1o$|M;hoZOG4XV(X-iOQa)#zt{v zMTL)8+w3MWdXX6qhONh6%+Ag_x|da-W07}nvz1Oc4`(;5?^k}kBR00p=3btH;XNG5 zdYCe@zjl5;9Z62UZfgaVRhvL zw!qq0^YHPjP2(pM3WjKI=Q9`b+84>a{d>N;R&uGP4VDreHXVPp7`WhhnK0v8l_4OW Q4YB-qgdq`dLvTXwUtlSuc@D@x2`n|m%g{QPe_3mHuxHpOy}>&ylYJjNG5%h3MySwFQDpY`es4a$Zs=Wc$nc{r_vKtE=o7tv38?T>;~avyjV%t3cpu^51bzy;RX@SE z5%+;~W2{>!(l`tl31^4bp&>FJK2>9Uzk`2(pTXwpAMouCe(d;D=bp?#f70(U?Ybz; zzfW$MrXcXaW_g}hSTC_&!It_yV^BHg_FJILv`|rqFvZ_?!V%K~5?-zi`|I#skxuNs z$XF;Xh*^r!atb}uUM#R(8nW0VG~=?g&4R|miqO*AN|rPcB4VBc8X-6 zosy$dL~>!L$ml9ty-cJKxo|`&v6?7==gjwV?%Qsl_qxr1CrLZjQ%#vRzH>l0^{LZ_ zg(GLAN0B8mrOMW{3Fn~(?kUl!N}{&ZwB}(raKrI+p1Rj2wq_7%6Er4vcvk}Q@t^h$ Xn*iFiJF8(400000NkvXXu0mjfRh=nX From 9a302328c63e9f6f89d6ac3efdfb37321b6c4bd3 Mon Sep 17 00:00:00 2001 From: Randall Luecke Date: Sat, 26 Jun 2010 23:35:33 -0500 Subject: [PATCH 61/61] Move the new close button a little to the right to confrom with the Aristo art. --- AppKit/CPWindow/_CPHUDWindowView.j | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppKit/CPWindow/_CPHUDWindowView.j b/AppKit/CPWindow/_CPHUDWindowView.j index ab9c283b4..f10167577 100644 --- a/AppKit/CPWindow/_CPHUDWindowView.j +++ b/AppKit/CPWindow/_CPHUDWindowView.j @@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0; { var closeSize = [_CPHUDWindowViewCloseImage size]; - _closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)]; + _closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)]; [_closeButton setBordered:NO];