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 | NS_DURING
|
---|
43 |
|
---|
44 | NSString *s = [self string];
|
---|
45 | unsigned length = [s length];
|
---|
46 | NSCAssert(s != nil && length != 0, ICCF_LocalizedString(@"No text was found"));
|
---|
47 |
|
---|
48 | ICCF_StartIC();
|
---|
49 |
|
---|
50 | // XXX handle discontiguous/rectangular selection with [self valueForKey: @"textSelectionRanges"] => NSIndexSet
|
---|
51 | NSCAssert(range.location < length, ICCF_LocalizedString(@"Sorry, ICeCoffEE was unable to find anything to select"));
|
---|
52 | if (range.length == 0) {
|
---|
53 | range.length = 1;
|
---|
54 | range = ICCF_URLEnclosingRange(s, range);
|
---|
55 | [self setSelectedRange: range];
|
---|
56 | }
|
---|
57 |
|
---|
58 | iccfURLAction keyboardAction = ICCF_KeyboardAction(triggeringEvent);
|
---|
59 | if (ICCF_LaunchURL([s substringWithRange: range], keyboardAction)) {
|
---|
60 | if (ICCF_prefs.textBlinkEnabled) {
|
---|
61 | for (unsigned i = 0 ; i < ICCF_prefs.textBlinkCount ; i++) {
|
---|
62 | [self clearTextSelection];
|
---|
63 | [self display];
|
---|
64 | usleep(kICBlinkDelayUsecs);
|
---|
65 | [self setSelectedRange: range];
|
---|
66 | [self display];
|
---|
67 | usleep(kICBlinkDelayUsecs);
|
---|
68 | }
|
---|
69 | }
|
---|
70 | } else if (keyboardAction.presentMenu) {
|
---|
71 | // mouse up used to cancel menu?
|
---|
72 | // XXX next click lost if Esc used; next drag behaves like Command-drag
|
---|
73 | ICCF_discardNextMouseUp = YES;
|
---|
74 | }
|
---|
75 |
|
---|
76 | NS_HANDLER
|
---|
77 | ICCF_HandleException(localException, triggeringEvent);
|
---|
78 | NS_ENDHANDLER
|
---|
79 |
|
---|
80 | ICCF_StopIC();
|
---|
81 | }
|
---|
82 |
|
---|
83 |
|
---|
84 | @implementation ICeCoffEETTView
|
---|
85 |
|
---|
86 | static NSEvent *ICCF_downEvent;
|
---|
87 |
|
---|
88 | - (void)mouseUp:(NSEvent *)upEvent;
|
---|
89 | {
|
---|
90 | if (ICCF_downEvent != nil) {
|
---|
91 | NSPoint downPt = [ICCF_downEvent locationInWindow];
|
---|
92 | NSPoint upPt = [upEvent locationInWindow];
|
---|
93 | if (abs(downPt.x - upPt.x) <= kICHysteresisPixels && abs(downPt.y - upPt.y) <= kICHysteresisPixels) {
|
---|
94 | [ICeCoffEETTViewTrigger setTriggerForEvent: ICCF_downEvent onTarget: self];
|
---|
95 | ICCF_discardNextMouseUp = YES; // otherwise Command-Option-click => cursor repositioning Option-click
|
---|
96 | }
|
---|
97 | [ICCF_downEvent release];
|
---|
98 | ICCF_downEvent = nil;
|
---|
99 | }
|
---|
100 | ICLog(@"ICeCoffEETTView up: %@", upEvent);
|
---|
101 | if (ICCF_discardNextMouseUp) {
|
---|
102 | ICCF_discardNextMouseUp = NO;
|
---|
103 | return;
|
---|
104 | }
|
---|
105 | [super mouseUp: upEvent];
|
---|
106 | }
|
---|
107 |
|
---|
108 | - (void)mouseDown:(NSEvent *)downEvent;
|
---|
109 | {
|
---|
110 | [ICeCoffEETrigger cancel];
|
---|
111 |
|
---|
112 | if (ICCF_enabled && ICCF_prefs.commandClickEnabled && ICCF_EventIsCommandMouseDown(downEvent)) {
|
---|
113 | [ICCF_downEvent release];
|
---|
114 | ICCF_downEvent = [downEvent retain];
|
---|
115 | }
|
---|
116 | ICLog(@"ICeCoffEETTView down: %@", downEvent);
|
---|
117 | [super mouseDown: downEvent];
|
---|
118 | }
|
---|
119 |
|
---|
120 | - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
|
---|
121 | {
|
---|
122 | if (!ICCF_prefs.terminalRequireOptionForSelfDrag || [sender draggingSource] != self || ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)) {
|
---|
123 | [super draggingEntered: sender];
|
---|
124 | // 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.
|
---|
125 | return NSDragOperationCopy;
|
---|
126 | }
|
---|
127 | return NSDragOperationNone;
|
---|
128 | }
|
---|
129 |
|
---|
130 | @end
|
---|