26 - (NSString *)cssString
28 NSColor *srgbColor = [
self colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
29 return [NSString stringWithFormat:@"rgba(%g,%g,%g,%g)",
30 255 * srgbColor.redComponent,
31 255 * srgbColor.greenComponent,
32 255 * srgbColor.blueComponent,
33 srgbColor.alphaComponent];
41 @property (retain, nonatomic) NSString *mostRecentText;
48 if (
self = [super init])
50 self.linkTextAttributes = @{ NSForegroundColorAttributeName:NSColor.secondaryLabelColor };
56 - (NSSize)intrinsicContentSize
58 [
self.layoutManager ensureLayoutForTextContainer:self.textContainer];
59 return [
self.layoutManager usedRectForTextContainer:self.textContainer].size;
64 [
super didChangeText];
65 [
self invalidateIntrinsicContentSize];
68 - (void)viewDidChangeEffectiveAppearance
70 [
self setText:self.mostRecentText];
73 - (void)setText:(NSString *)text
76 NSMutableString *s = [NSMutableString new];
77 [s appendString:@"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"];
79 [NSAppearance setCurrentAppearance:self.effectiveAppearance];
80 NSString *headingCSS = NSColor.labelColor.cssString;
81 NSString *subheadingCSS = NSColor.tertiaryLabelColor.cssString;
82 NSString *bodyCSS = NSColor.secondaryLabelColor.cssString;
84 [s appendFormat:@"<style> \
85 body { font: 10pt 'Helvetica Neue'; color: %@; } \
86 p { padding-top: 30px; } \
87 h1 { padding-top: 30px; } \
88 .name { font-size: 28pt; font-weight: 300; } \
89 .version { color: %@; font-size: 22pt; font-weight: 200; } \
90 .copyright { color: %@; } \
91 .description { font-weight: bold; } \
92 .licenses { color: %@; font-size: 8pt; } \
93 pre { font: 'Monaco'; } \
99 [s appendString:text];
100 NSAttributedString *as = [[NSAttributedString alloc] initWithHTML:[s dataUsingEncoding:NSUTF8StringEncoding] documentAttributes:nil];
102 self.textStorage.mutableString.string =
@"";
103 [
self.textStorage appendAttributedString:as];
117 - (void)cancelOperation:(
id)sender
134 if (
self = [super initWithContentRect:NSMakeRect(0, 0, 820, 500)
135 styleMask:NSTitledWindowMask|NSClosableWindowMask|NSFullSizeContentViewWindowMask
136 backing:NSBackingStoreBuffered
139 self.releasedWhenClosed = NO;
140 self.titlebarAppearsTransparent = YES;
143 NSBox *leftColumn = [NSBox new];
144 leftColumn.translatesAutoresizingMaskIntoConstraints = NO;
145 leftColumn.boxType = NSBoxCustom;
146 leftColumn.borderType = NSNoBorder;
147 leftColumn.fillColor = NSColor.controlBackgroundColor;
151 NSImageView *icon = [NSImageView new];
152 icon.translatesAutoresizingMaskIntoConstraints = NO;
153 icon.image = NSApplication.sharedApplication.applicationIconImage;
154 [leftColumn addSubview:icon];
157 poweredByVuo.translatesAutoresizingMaskIntoConstraints = NO;
158 poweredByVuo.borderVisible = NO;
159 [leftColumn addSubview:poweredByVuo];
161 NSDictionary *views = NSDictionaryOfVariableBindings(icon, poweredByVuo);
162 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[icon(160)]-|" options:0 metrics:nil views:views]];
163 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[poweredByVuo]-|" options:0 metrics:nil views:views]];
164 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[icon(160)]-(>=0)-[poweredByVuo(120)]-|" options:0 metrics:nil views:views]];
166 [poweredByVuo release];
171 NSBox *rightColumn = [NSBox new];
172 rightColumn.translatesAutoresizingMaskIntoConstraints = NO;
173 rightColumn.boxType = NSBoxCustom;
174 rightColumn.borderType = NSNoBorder;
175 rightColumn.fillColor = NSColor.windowBackgroundColor;
181 description.frame = NSMakeRect(0, 0, 560, 0);
182 description.translatesAutoresizingMaskIntoConstraints = NO;
183 description.drawsBackground = NO;
185 NSMutableString *s = [NSMutableString new];
187 NSString *name = NSBundle.mainBundle.infoDictionary[@"CFBundleName"];
189 name = NSProcessInfo.processInfo.processName;
190 [s appendFormat:@"<span class='name'>%@</span>", name];
192 NSString *version = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
194 [s appendFormat:@" <span class='version'>%@</span>", version];
196 NSString *copyright = NSBundle.mainBundle.infoDictionary[@"NSHumanReadableCopyright"];
198 [s appendFormat:@"<p class='copyright'>%@</p>", copyright];
200 NSString *desc = NSBundle.mainBundle.infoDictionary[@"description"];
202 [s appendFormat:@"<div class='description'>%@</div><br>", desc];
204 NSString *homepage = NSBundle.mainBundle.infoDictionary[@"homepageURL"];
205 NSString *documentation = NSBundle.mainBundle.infoDictionary[@"documentationURL"];
207 [s appendFormat:@"<p><a href='%@'>%@</a></p>", homepage, homepage];
209 [s appendFormat:@"<p><a href='%@'>%@</a></p>", documentation, documentation];
211 [description setText:s];
214 [rightColumn addSubview:description];
220 NSMutableString *s = [NSMutableString new];
221 [s appendString:@"<div class='licenses'>"];
222 [s appendString:[
self licenseString]];
223 [s appendString:@"</div>"];
224 [licenses setText:s];
227 NSScrollView *licensesScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 20, 560, 280)];
228 licensesScroller.hasVerticalScroller = YES;
229 licensesScroller.documentView = licenses;
230 licenses.frame = NSMakeRect(0, 0, licensesScroller.contentSize.width, licensesScroller.contentSize.height);
231 [rightColumn addSubview:licensesScroller];
234 NSDictionary *views = NSDictionaryOfVariableBindings(description, licensesScroller);
235 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[description]-|" options:0 metrics:nil views:views]];
236 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[licensesScroller]-|" options:0 metrics:nil views:views]];
237 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[description][licensesScroller]-|" options:0 metrics:nil views:views]];
240 [licensesScroller release];
241 [description release];
246 self.contentView = c;
247 [c addSubview:leftColumn];
248 [c addSubview:rightColumn];
250 NSDictionary *views = NSDictionaryOfVariableBindings(leftColumn,rightColumn);
251 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[leftColumn][rightColumn]|" options:0 metrics:nil views:views]];
252 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[leftColumn]|" options:0 metrics:nil views:views]];
253 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[rightColumn]|" options:0 metrics:nil views:views]];
256 [leftColumn release];
257 [rightColumn release];
266 - (NSString *)licenseString
268 NSMutableString *s = [NSMutableString new];
271 [s appendString:@"<p>This app may include software and resources licensed under the following terms:</p>"];
275 char licensesPath[PATH_MAX+1];
280 strncat(licensesPath,
"/Vuo.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING
"/Documentation/Licenses", PATH_MAX);
285 strncat(licensesPath,
"/VuoRunner.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING
"/Documentation/Licenses", PATH_MAX);
289 bool foundLicenses =
false;
290 DIR *dirp = licensesPath[0] ? opendir(licensesPath) : NULL;
294 while ((dp = readdir(dirp)) != NULL)
296 if (dp->d_name[0] ==
'.')
299 char *nameWithoutExtension = strdup(dp->d_name);
300 nameWithoutExtension[strlen(nameWithoutExtension) - 4] = 0;
301 [s appendString:[NSString stringWithFormat:@"<h2>%s</h2>", nameWithoutExtension]];
302 free(nameWithoutExtension);
304 size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
305 char licensePath[pathSize];
306 strlcpy(licensePath, licensesPath, pathSize);
307 strlcat(licensePath,
"/", pathSize);
308 strlcat(licensePath, dp->d_name, pathSize);
310 [s appendString:[NSString stringWithFormat:@"<pre>%@</pre><br>",
311 [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:licensePath] usedEncoding:nil error:nil]]];
313 foundLicenses =
true;
319 [s appendString:@"<p>(No license information found.)</p>"];
321 return [s autorelease];
330 @property(nonatomic, strong) NSWindow *window;
338 - (void)displayAboutPanel:(
id)sender
343 [_window makeKeyAndOrderFront:sender];