27 - (NSString *)cssString
29 NSColor *srgbColor = [
self colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
30 return [NSString stringWithFormat:@"rgba(%g,%g,%g,%g)",
31 255 * srgbColor.redComponent,
32 255 * srgbColor.greenComponent,
33 255 * srgbColor.blueComponent,
34 srgbColor.alphaComponent];
42 @property (retain, nonatomic) NSString *mostRecentText;
49 if (
self = [super init])
51 self.linkTextAttributes = @{ NSForegroundColorAttributeName:NSColor.secondaryLabelColor };
57 - (NSSize)intrinsicContentSize
59 [
self.layoutManager ensureLayoutForTextContainer:self.textContainer];
60 return [
self.layoutManager usedRectForTextContainer:self.textContainer].size;
65 [
super didChangeText];
66 [
self invalidateIntrinsicContentSize];
69 - (void)viewDidChangeEffectiveAppearance
71 [
self setText:self.mostRecentText];
74 - (void)setText:(NSString *)text
77 NSMutableString *s = [NSMutableString new];
78 [s appendString:@"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"];
80 [NSAppearance setCurrentAppearance:self.effectiveAppearance];
81 NSString *headingCSS = NSColor.labelColor.cssString;
82 NSString *subheadingCSS = NSColor.tertiaryLabelColor.cssString;
83 NSString *bodyCSS = NSColor.secondaryLabelColor.cssString;
85 [s appendFormat:@"<style> \
86 body { font: 10pt 'Helvetica Neue'; color: %@; } \
87 p { padding-top: 30px; } \
88 h1 { padding-top: 30px; } \
89 .name { font-size: 28pt; font-weight: 300; } \
90 .version { color: %@; font-size: 22pt; font-weight: 200; } \
91 .copyright { color: %@; } \
92 .description { font-weight: bold; } \
93 .licenses { color: %@; font-size: 8pt; } \
94 pre { font: 'Monaco'; } \
100 [s appendString:text];
101 NSAttributedString *as = [[NSAttributedString alloc] initWithHTML:[s dataUsingEncoding:NSUTF8StringEncoding] documentAttributes:nil];
103 self.textStorage.mutableString.string =
@"";
104 [
self.textStorage appendAttributedString:as];
118 - (void)cancelOperation:(
id)sender
135 if (
self = [super initWithContentRect:NSMakeRect(0, 0, 820, 500)
136 styleMask:NSTitledWindowMask|NSClosableWindowMask|NSFullSizeContentViewWindowMask
137 backing:NSBackingStoreBuffered
140 self.releasedWhenClosed = NO;
141 self.titlebarAppearsTransparent = YES;
144 NSBox *leftColumn = [NSBox new];
145 leftColumn.translatesAutoresizingMaskIntoConstraints = NO;
146 leftColumn.boxType = NSBoxCustom;
147 leftColumn.borderType = NSNoBorder;
148 leftColumn.fillColor = NSColor.controlBackgroundColor;
152 NSImageView *icon = [NSImageView new];
153 icon.translatesAutoresizingMaskIntoConstraints = NO;
154 icon.image = NSApplication.sharedApplication.applicationIconImage;
155 [leftColumn addSubview:icon];
158 poweredByVuo.translatesAutoresizingMaskIntoConstraints = NO;
159 poweredByVuo.borderVisible = NO;
160 [leftColumn addSubview:poweredByVuo];
162 NSDictionary *views = NSDictionaryOfVariableBindings(icon, poweredByVuo);
163 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[icon(160)]-|" options:0 metrics:nil views:views]];
164 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[poweredByVuo]-|" options:0 metrics:nil views:views]];
165 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[icon(160)]-(>=0)-[poweredByVuo(120)]-|" options:0 metrics:nil views:views]];
167 [poweredByVuo release];
172 NSBox *rightColumn = [NSBox new];
173 rightColumn.translatesAutoresizingMaskIntoConstraints = NO;
174 rightColumn.boxType = NSBoxCustom;
175 rightColumn.borderType = NSNoBorder;
176 rightColumn.fillColor = NSColor.windowBackgroundColor;
182 description.frame = NSMakeRect(0, 0, 560, 0);
183 description.translatesAutoresizingMaskIntoConstraints = NO;
184 description.drawsBackground = NO;
186 NSMutableString *s = [NSMutableString new];
188 NSString *name = NSBundle.mainBundle.infoDictionary[@"CFBundleName"];
190 name = NSProcessInfo.processInfo.processName;
191 [s appendFormat:@"<span class='name'>%@</span>", name];
193 NSString *version = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
195 [s appendFormat:@" <span class='version'>%@</span>", version];
197 NSString *copyright = NSBundle.mainBundle.infoDictionary[@"NSHumanReadableCopyright"];
199 [s appendFormat:@"<p class='copyright'>%@</p>", copyright];
201 NSString *desc = NSBundle.mainBundle.infoDictionary[@"description"];
203 [s appendFormat:@"<div class='description'>%@</div><br>", desc];
205 NSString *homepage = NSBundle.mainBundle.infoDictionary[@"homepageURL"];
206 NSString *documentation = NSBundle.mainBundle.infoDictionary[@"documentationURL"];
208 [s appendFormat:@"<p><a href='%@'>%@</a></p>", homepage, homepage];
210 [s appendFormat:@"<p><a href='%@'>%@</a></p>", documentation, documentation];
212 [description setText:s];
215 [rightColumn addSubview:description];
221 NSMutableString *s = [NSMutableString new];
222 [s appendString:@"<div class='licenses'>"];
223 [s appendString:[
self licenseString]];
224 [s appendString:@"</div>"];
225 [licenses setText:s];
228 NSScrollView *licensesScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 20, 560, 280)];
229 licensesScroller.hasVerticalScroller = YES;
230 licensesScroller.documentView = licenses;
231 licenses.frame = NSMakeRect(0, 0, licensesScroller.contentSize.width, licensesScroller.contentSize.height);
232 [rightColumn addSubview:licensesScroller];
235 NSDictionary *views = NSDictionaryOfVariableBindings(description, licensesScroller);
236 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[description]-|" options:0 metrics:nil views:views]];
237 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[licensesScroller]-|" options:0 metrics:nil views:views]];
238 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[description][licensesScroller]-|" options:0 metrics:nil views:views]];
241 [licensesScroller release];
242 [description release];
247 self.contentView = c;
248 [c addSubview:leftColumn];
249 [c addSubview:rightColumn];
251 NSDictionary *views = NSDictionaryOfVariableBindings(leftColumn,rightColumn);
252 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[leftColumn][rightColumn]|" options:0 metrics:nil views:views]];
253 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[leftColumn]|" options:0 metrics:nil views:views]];
254 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[rightColumn]|" options:0 metrics:nil views:views]];
257 [leftColumn release];
258 [rightColumn release];
267 - (NSString *)licenseString
269 NSMutableString *s = [NSMutableString new];
272 [s appendString:@"<p>This app may include software and resources licensed under the following terms:</p>"];
276 char licensesPath[PATH_MAX+1];
281 strncat(licensesPath,
"/Vuo.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING
"/Documentation/Licenses", PATH_MAX);
286 strncat(licensesPath,
"/VuoRunner.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING
"/Documentation/Licenses", PATH_MAX);
290 bool foundLicenses =
false;
291 DIR *dirp = licensesPath[0] ? opendir(licensesPath) : NULL;
295 while ((dp = readdir(dirp)) != NULL)
297 if (dp->d_name[0] ==
'.')
300 char *nameWithoutExtension = strdup(dp->d_name);
301 nameWithoutExtension[strlen(nameWithoutExtension) - 4] = 0;
302 [s appendString:[NSString stringWithFormat:@"<h2>%s</h2>", nameWithoutExtension]];
303 free(nameWithoutExtension);
305 size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
306 char licensePath[pathSize];
307 strlcpy(licensePath, licensesPath, pathSize);
308 strlcat(licensePath,
"/", pathSize);
309 strlcat(licensePath, dp->d_name, pathSize);
311 [s appendString:[NSString stringWithFormat:@"<pre>%@</pre><br>",
312 [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:licensePath] usedEncoding:nil error:nil]]];
314 foundLicenses =
true;
320 [s appendString:@"<p>(No license information found.)</p>"];
322 return [s autorelease];
331 @property(nonatomic, strong) NSWindow *window;
339 - (void)displayAboutPanel:(
id)sender
344 [_window makeKeyAndOrderFront:sender];