// // ICeCoffEETTView.m // ICeCoffEE // // Created by Nicholas Riley on 2/21/08. // Copyright 2008 Nicholas Riley. All rights reserved. // #import "ICeCoffEETTView.h" #import "ICeCoffEE.h" #import "ICeCoffEEParser.h" #import "ICeCoffEETTViewTrigger.h" #include static NSRange ICCF_zeroRange = { NSNotFound, 5 }; @implementation ICeCoffEETTViewSuper // NSTextInput implementation - (void)insertText:(id)aString {} - (void)doCommandBySelector:(SEL)aSelector {} - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {} - (void)unmarkText {} - (BOOL)hasMarkedText { return NO; } - (long)conversationIdentifier { return 0; } - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange { return nil; } - (NSRange)markedRange { return ICCF_zeroRange; } - (NSRange)selectedRange { return ICCF_zeroRange; } - (NSRect)firstRectForCharacterRange:(NSRange)theRange { return NSZeroRect; } - (unsigned int)characterIndexForPoint:(NSPoint)thePoint { return 0; } - (NSArray*)validAttributesForMarkedText { return nil; } // Selection - (void)clearTextSelection {} - (void)setSelectedRange:(NSRange)charRange {} // misc. other stuff - (NSString *)string { return nil; } @end static BOOL ICCF_discardNextMouseUp = NO; void ICCF_LaunchURLFromTTView(ICeCoffEETTView *self, NSEvent *triggeringEvent, NSRange range) { @try { NSString *s = [self string]; unsigned length = [s length]; NSCAssert(s != nil && length != 0, ICCF_LocalizedString(@"No text was found")); ICCF_StartIC(); // XXX handle discontiguous/rectangular selection with [self valueForKey: @"textSelectionRanges"] => NSIndexSet NSCAssert(range.location < length, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select")); if (range.length == 0) { range.length = 1; range = ICCF_URLEnclosingRange(s, range); [self setSelectedRange: range]; } iccfURLAction keyboardAction = ICCF_KeyboardAction(triggeringEvent); if (ICCF_LaunchURL([s substringWithRange: range], keyboardAction)) { if (ICCF_prefs.textBlinkEnabled) { for (unsigned i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) { [self clearTextSelection]; [self display]; usleep(kICBlinkDelayUsecs); [self setSelectedRange: range]; [self display]; usleep(kICBlinkDelayUsecs); } } } else if (keyboardAction.presentMenu) { // mouse up used to cancel menu? // XXX next click lost if Esc used; next drag behaves like Command-drag ICCF_discardNextMouseUp = YES; } } @catch (NSException *e) { ICCF_HandleException(e, triggeringEvent); } ICCF_StopIC(); } @implementation ICeCoffEETTView static NSEvent *ICCF_downEvent; - (void)mouseUp:(NSEvent *)upEvent; { if (ICCF_downEvent != nil) { NSPoint downPt = [ICCF_downEvent locationInWindow]; NSPoint upPt = [upEvent locationInWindow]; if (abs(downPt.x - upPt.x) <= kICHysteresisPixels && abs(downPt.y - upPt.y) <= kICHysteresisPixels) { [ICeCoffEETTViewTrigger setTriggerForEvent: ICCF_downEvent onTarget: self]; ICCF_discardNextMouseUp = YES; // otherwise Command-Option-click => cursor repositioning Option-click } [ICCF_downEvent release]; ICCF_downEvent = nil; } ICLog(@"ICeCoffEETTView up: %@", upEvent); if (ICCF_discardNextMouseUp) { ICCF_discardNextMouseUp = NO; return; } [super mouseUp: upEvent]; } - (void)mouseDown:(NSEvent *)downEvent; { [ICeCoffEETrigger cancel]; if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(downEvent)) { [ICCF_downEvent release]; ICCF_downEvent = [downEvent retain]; } ICLog(@"ICeCoffEETTView down: %@", downEvent); [super mouseDown: downEvent]; } - (NSDragOperation)draggingEntered:(id )sender; { if (!ICCF_prefs.terminalRequireOptionForSelfDrag || [sender draggingSource] != self || ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)) { [super draggingEntered: sender]; // When doing non-self drags, this works around one bug in Terminal wherein the option key acts as a toggle, and it shouldn't (see Aqua HIG). Unfortunately, this messes up drag feedback for self drags, but I don't know of any way to fix it. Not that most Cocoa apps get it remotely right, anyway. return NSDragOperationCopy; } return NSDragOperationNone; } @end