1 | // |
---|
2 | // ICeCoffEETTView.m |
---|
3 | // ICeCoffEE |
---|
4 | // |
---|
5 | // Created by Nicholas Riley on 2/21/08. |
---|
6 | // Copyright 2008 Nicholas Riley. All rights reserved. |
---|
7 | // |
---|
8 | |
---|
9 | #import "ICeCoffEETTView.h" |
---|
10 | #import "ICeCoffEE.h" |
---|
11 | #import "ICeCoffEEParser.h" |
---|
12 | #import "ICeCoffEETTViewTrigger.h" |
---|
13 | #include <unistd.h> |
---|
14 | |
---|
15 | static NSRange ICCF_zeroRange = { NSNotFound, 5 }; |
---|
16 | |
---|
17 | @implementation ICeCoffEETTViewSuper |
---|
18 | // NSTextInput implementation |
---|
19 | - (void)insertText:(id)aString {} |
---|
20 | - (void)doCommandBySelector:(SEL)aSelector {} |
---|
21 | - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange {} |
---|
22 | - (void)unmarkText {} |
---|
23 | - (BOOL)hasMarkedText { return NO; } |
---|
24 | - (long)conversationIdentifier { return 0; } |
---|
25 | - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange { return nil; } |
---|
26 | - (NSRange)markedRange { return ICCF_zeroRange; } |
---|
27 | - (NSRange)selectedRange { return ICCF_zeroRange; } |
---|
28 | - (NSRect)firstRectForCharacterRange:(NSRange)theRange { return NSZeroRect; } |
---|
29 | - (unsigned int)characterIndexForPoint:(NSPoint)thePoint { return 0; } |
---|
30 | - (NSArray*)validAttributesForMarkedText { return nil; } |
---|
31 | // Selection |
---|
32 | - (void)clearTextSelection {} |
---|
33 | - (void)setSelectedRange:(NSRange)charRange {} |
---|
34 | // misc. other stuff |
---|
35 | - (NSString *)string { return nil; } |
---|
36 | @end |
---|
37 | |
---|
38 | static BOOL ICCF_discardNextMouseUp = NO; |
---|
39 | |
---|
40 | void ICCF_LaunchURLFromTTView(ICeCoffEETTView *self, NSEvent *triggeringEvent, NSRange range) { |
---|
41 | |
---|
42 | @try { |
---|
43 | NSString *s = [self string]; |
---|
44 | unsigned length = [s length]; |
---|
45 | NSCAssert(s != nil && length != 0, ICCF_LocalizedString(@"No text was found")); |
---|
46 | |
---|
47 | ICCF_StartIC(); |
---|
48 | |
---|
49 | // XXX handle discontiguous/rectangular selection with [self valueForKey: @"textSelectionRanges"] => NSIndexSet |
---|
50 | NSCAssert(range.location < length, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select")); |
---|
51 | if (range.length == 0) { |
---|
52 | range.length = 1; |
---|
53 | range = ICCF_URLEnclosingRange(s, range); |
---|
54 | [self setSelectedRange: range]; |
---|
55 | } |
---|
56 | |
---|
57 | iccfURLAction keyboardAction = ICCF_KeyboardAction(triggeringEvent); |
---|
58 | if (ICCF_LaunchURL([s substringWithRange: range], keyboardAction)) { |
---|
59 | if (ICCF_prefs.textBlinkEnabled) { |
---|
60 | for (unsigned i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) { |
---|
61 | [self clearTextSelection]; |
---|
62 | [self display]; |
---|
63 | usleep(kICBlinkDelayUsecs); |
---|
64 | [self setSelectedRange: range]; |
---|
65 | [self display]; |
---|
66 | usleep(kICBlinkDelayUsecs); |
---|
67 | } |
---|
68 | } |
---|
69 | } else if (keyboardAction.presentMenu) { |
---|
70 | // mouse up used to cancel menu? |
---|
71 | // XXX next click lost if Esc used; next drag behaves like Command-drag |
---|
72 | ICCF_discardNextMouseUp = YES; |
---|
73 | } |
---|
74 | } @catch (NSException *e) { |
---|
75 | ICCF_HandleException(e, triggeringEvent); |
---|
76 | } |
---|
77 | |
---|
78 | ICCF_StopIC(); |
---|
79 | } |
---|
80 | |
---|
81 | |
---|
82 | @implementation ICeCoffEETTView |
---|
83 | |
---|
84 | static NSEvent *ICCF_downEvent; |
---|
85 | |
---|
86 | - (void)mouseUp:(NSEvent *)upEvent; |
---|
87 | { |
---|
88 | if (ICCF_downEvent != nil) { |
---|
89 | NSPoint downPt = [ICCF_downEvent locationInWindow]; |
---|
90 | NSPoint upPt = [upEvent locationInWindow]; |
---|
91 | if (abs(downPt.x - upPt.x) <= kICHysteresisPixels && abs(downPt.y - upPt.y) <= kICHysteresisPixels) { |
---|
92 | [ICeCoffEETTViewTrigger setTriggerForEvent: ICCF_downEvent onTarget: self]; |
---|
93 | ICCF_discardNextMouseUp = YES; // otherwise Command-Option-click => cursor repositioning Option-click |
---|
94 | } |
---|
95 | [ICCF_downEvent release]; |
---|
96 | ICCF_downEvent = nil; |
---|
97 | } |
---|
98 | ICLog(@"ICeCoffEETTView up: %@", upEvent); |
---|
99 | if (ICCF_discardNextMouseUp) { |
---|
100 | ICCF_discardNextMouseUp = NO; |
---|
101 | return; |
---|
102 | } |
---|
103 | [super mouseUp: upEvent]; |
---|
104 | } |
---|
105 | |
---|
106 | - (void)mouseDown:(NSEvent *)downEvent; |
---|
107 | { |
---|
108 | [ICeCoffEETrigger cancel]; |
---|
109 | |
---|
110 | if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(downEvent)) { |
---|
111 | [ICCF_downEvent release]; |
---|
112 | ICCF_downEvent = [downEvent retain]; |
---|
113 | } |
---|
114 | ICLog(@"ICeCoffEETTView down: %@", downEvent); |
---|
115 | [super mouseDown: downEvent]; |
---|
116 | } |
---|
117 | |
---|
118 | - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender; |
---|
119 | { |
---|
120 | if (!ICCF_prefs.terminalRequireOptionForSelfDrag || [sender draggingSource] != self || ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)) { |
---|
121 | [super draggingEntered: sender]; |
---|
122 | // 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. |
---|
123 | return NSDragOperationCopy; |
---|
124 | } |
---|
125 | return NSDragOperationNone; |
---|
126 | } |
---|
127 | |
---|
128 | @end |
---|