Vuo 2.4.4
Loading...
Searching...
No Matches
VuoWindowTextInternal.m
Go to the documentation of this file.
11#import "VuoWindow.h"
12#import "VuoApp.h"
13
14#include <dispatch/dispatch.h>
15
16#ifdef VUO_COMPILER
18 "title" : "VuoWindowTextInternal",
19 "dependencies" : [
20 "AppKit.framework",
21 "VuoWindow"
22 ]
23 });
24#endif
25
26
27@implementation VuoWindowTextInternal
28
29@synthesize textView;
30@synthesize scrollView;
31@synthesize textFont;
32@synthesize editCopyMenuItem;
33@synthesize editSelectAllMenuItem;
34@synthesize editClearMenuItem;
35
41- (id)init
42{
43 NSRect frame = NSMakeRect(0, 0, 400, 600);
44 NSUInteger styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
45 NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:styleMask];
46
47 if (self = [super initWithContentRect:contentRect
48 styleMask:styleMask
49 backing:NSBackingStoreBuffered
50 defer:NO])
51 {
52 triggersEnabled = NO;
53 typedLine = NULL;
54 typedWord = NULL;
55 typedCharacter = NULL;
56
57 self.delegate = self;
58 self.releasedWhenClosed = NO;
59
60 char *title = VuoApp_getName();
61 [self setTitle:[NSString stringWithUTF8String:title]];
62 free(title);
63
64 NSFont *_textFont = [NSFont fontWithName:@"Monaco" size:0];
65 self.textFont = _textFont;
66
67 NSScrollView *_scrollView = [[NSScrollView alloc] initWithFrame:[[self contentView] frame]];
68 self.scrollView = _scrollView;
69 [_scrollView release];
70 [scrollView setHasVerticalScroller:YES];
71 [scrollView setAutohidesScrollers:NO];
72 [scrollView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
73 [self setContentView:scrollView];
74
75 NSTextView *_textView = [[NSTextView alloc] initWithFrame:[[scrollView contentView] frame]];
76 self.textView = _textView;
77 [_textView release];
78 [textView setFont:textFont];
79 [textView setEditable:YES];
80 [textView setAllowsUndo:NO];
81 [textView setAutoresizingMask:NSViewWidthSizable];
82 [textView setAutomaticDashSubstitutionEnabled:NO];
83 [textView setAutomaticDataDetectionEnabled:NO];
84 [textView setAutomaticLinkDetectionEnabled:NO];
85 [textView setAutomaticQuoteSubstitutionEnabled:NO];
86 [textView setAutomaticSpellingCorrectionEnabled:NO];
87 [textView setAutomaticTextReplacementEnabled:NO];
88 [scrollView setDocumentView:textView];
89
90 // Remove the "Cut" option from the context menu.
91 NSMenu *textViewContextMenu = [textView menu];
92 int cutItemIndex = [textViewContextMenu indexOfItemWithTitle: @"Cut"];
93 if (cutItemIndex >= 0)
94 [textViewContextMenu removeItemAtIndex: cutItemIndex];
95
96 // Remove the "Paste" option from the context menu.
97 int pasteItemIndex = [textViewContextMenu indexOfItemWithTitle: @"Paste"];
98 if (pasteItemIndex >= 0)
99 [textViewContextMenu removeItemAtIndex: pasteItemIndex];
100
101 textView.delegate = self;
102 }
103 return self;
104}
105
113- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString
114{
115 // Allow inserting multi-keystroke (e.g. accented) characters.
116 NSUInteger markedTextLength = [aTextView markedRange].length;
117
118 // Disallow inserting characters anywhere but at the end.
119 if (affectedCharRange.location + markedTextLength != [[textView string] length])
120 return NO;
121
122 if (! triggersEnabled)
123 return YES;
124
125 // Don't fire events for partial multi-keystroke characters.
126 if ([aTextView hasMarkedText] && markedTextLength == 0)
127 return YES;
128
129 for (NSUInteger i = 0; i < [replacementString length]; ++i)
130 {
131 unichar charTyped = [replacementString characterAtIndex:i];
132
133 // Fire event for character.
134 VuoText charTypedAsText = VuoText_make([[NSString stringWithCharacters:&charTyped length:1] UTF8String]);
135 typedCharacter(charTypedAsText);
136
137 // If user typed whitespace...
138 if ([[NSCharacterSet whitespaceAndNewlineCharacterSet] characterIsMember:charTyped])
139 {
140 // ... and if it ends a word, then fire event for word.
141 NSRange previousWhitespaceOrNewline = [[textView string] rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]
142 options:NSBackwardsSearch];
143 NSUInteger previousWordStart = (previousWhitespaceOrNewline.location != NSNotFound ?
144 previousWhitespaceOrNewline.location + 1 :
145 0);
146 if (previousWordStart < [[textView string] length])
147 {
148 NSString *wordTyped = [[textView string] substringFromIndex:previousWordStart];
149 VuoText wordTypedAsText = VuoText_make([wordTyped UTF8String]);
150 typedWord(wordTypedAsText);
151 }
152 }
153
154 // If user typed a newline...
155 if ([[NSCharacterSet newlineCharacterSet] characterIsMember:charTyped])
156 {
157 // ... and if it ends a line, then fire event for line.
158 NSRange previousNewline = [[textView string] rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]
159 options:NSBackwardsSearch];
160 NSUInteger previousLineStart = (previousNewline.location != NSNotFound ?
161 previousNewline.location + 1 :
162 0);
163 if (previousLineStart < [[textView string] length])
164 {
165 NSString *lineTyped = [[textView string] substringFromIndex:previousLineStart];
166 VuoText lineTypedAsText = VuoText_make([lineTyped UTF8String]);
167 typedLine(lineTypedAsText);
168 }
169 }
170 }
171
172 return YES;
173}
174
178- (void)becomeMainWindow
179{
180 [super becomeMainWindow];
181
182 NSMenu *editMenu = [[[NSMenu alloc] initWithTitle:@"Edit"] autorelease];
183
184 // "Edit > Copy"
185 self.editCopyMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copyText) keyEquivalent:@"c"] autorelease];
186 [self.editCopyMenuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
187 [editMenu addItem:self.editCopyMenuItem];
188
189 // "Edit > Select All"
190 self.editSelectAllMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Select All" action:@selector(selectAllText) keyEquivalent:@"a"] autorelease];
191 [self.editSelectAllMenuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
192 [editMenu addItem:self.editSelectAllMenuItem];
193
194 // "Edit > Clear"
195 self.editClearMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Clear" action:@selector(clear) keyEquivalent:@"k"] autorelease];
196 [self.editClearMenuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
197 [editMenu addItem:self.editClearMenuItem];
198
199 NSMenuItem *editMenuItem = [[NSMenuItem new] autorelease];
200 [editMenuItem setSubmenu:editMenu];
201
202 NSMutableArray *windowMenuItems = [NSMutableArray arrayWithCapacity:2];
203 [windowMenuItems addObject:editMenuItem];
204 oldMenu = [(NSMenu *)VuoApp_setMenuItems(windowMenuItems) retain];
205}
206
210- (void)resignMainWindow
211{
212 [super resignMainWindow];
213
215 [oldMenu release];
216 oldMenu = nil;
217}
218
222- (void)windowWillClose:(NSNotification *)notification
223{
224 [super resignMainWindow];
225
227 [oldMenu release];
228 oldMenu = nil;
229}
230
234- (void)enableTriggersWithTypedLine:(void (*)(VuoText))_typedLine
235 typedWord:(void (*)(VuoText))_typedWord
236 typedCharacter:(void (*)(VuoText))_typedCharacter
237{
238 triggersEnabled = YES;
239 typedLine = _typedLine;
240 typedWord = _typedWord;
241 typedCharacter = _typedCharacter;
242}
243
247- (void)disableTriggers
248{
249 triggersEnabled = NO;
250 typedLine = NULL;
251 typedWord = NULL;
252 typedCharacter = NULL;
253}
254
258- (void)appendLine:(const char *)text
259{
260 // Autoscroll the window only if the viewport was already at the end.
261 BOOL autoscroll = fabs(NSMaxY(textView.visibleRect) - NSMaxY(textView.bounds)) < 1;
262
263 NSString *line = [[NSString stringWithUTF8String:text] stringByAppendingString:@"\n"];
264 if (!line)
265 {
266 VUserLog("Warning: Attempting to write non-UTF-8 text to a console window. Ignoring.");
267 return;
268 }
269
270 NSDictionary *attributes = @{
271 NSFontAttributeName: textFont,
272 NSForegroundColorAttributeName: NSColor.textColor,
273 };
274 NSAttributedString *attributedLine = [[NSAttributedString alloc] initWithString:line attributes:attributes];
275 [[textView textStorage] appendAttributedString:attributedLine];
276 [attributedLine release];
277
278 NSTextContainer *textContainer = [textView textContainer];
279 NSLayoutManager *layoutManager = [textView layoutManager];
280 [layoutManager ensureLayoutForTextContainer:textContainer];
281 NSRect frameToFitText = [layoutManager usedRectForTextContainer:textContainer];
282 [textView setFrame:frameToFitText];
283
284 if (autoscroll)
285 [textView scrollRangeToVisible:NSMakeRange([[textView string] length], 0)];
286}
287
291- (void)clear
292{
293 [textView.textStorage deleteCharactersInRange:NSMakeRange(0, textView.textStorage.length)];
294}
295
299- (void)copyText
300{
301 bool hasSelectedText = ([textView selectedRange].length > 0);
302 if (hasSelectedText)
303 [self.textView copy:self];
304}
305
309- (void)selectAllText
310{
311 [self.textView selectAll:self];
312}
313
318- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
319{
320 SEL theAction = [anItem action];
321 if (theAction == @selector(copyText)) {
322
323 bool hasSelectedText = ([textView selectedRange].length > 0);
324 return hasSelectedText;
325 }
326
327 return [super validateUserInterfaceItem:anItem];
328}
329
330@end