20@interface NSColor (VuoAppAboutBox)
23@implementation NSColor (VuoAppAboutBox)
24- (NSString *)cssString
26 NSColor *srgbColor = [
self colorUsingColorSpace:NSColorSpace.sRGBColorSpace];
27 return [NSString stringWithFormat:@"rgba(%g,%g,%g,%g)",
28 255 * srgbColor.redComponent,
29 255 * srgbColor.greenComponent,
30 255 * srgbColor.blueComponent,
31 srgbColor.alphaComponent];
39@property (retain, nonatomic) NSString *mostRecentText;
46 if (
self = [super init])
48 self.linkTextAttributes = @{ NSForegroundColorAttributeName:NSColor.secondaryLabelColor };
54- (NSSize)intrinsicContentSize
56 [
self.layoutManager ensureLayoutForTextContainer:self.textContainer];
57 return [
self.layoutManager usedRectForTextContainer:self.textContainer].size;
62 [
super didChangeText];
63 [
self invalidateIntrinsicContentSize];
66- (void)viewDidChangeEffectiveAppearance
68 [
self setText:self.mostRecentText];
71- (void)setText:(NSString *)text
73 self.mostRecentText = text;
74 NSMutableString *s = [NSMutableString new];
75 [s appendString:@"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"];
77 NSString *headingCSS = NSColor.labelColor.cssString;
78 NSString *subheadingCSS = NSColor.tertiaryLabelColor.cssString;
79 NSString *bodyCSS = NSColor.secondaryLabelColor.cssString;
81 [s appendFormat:@"<style> \
82 body { font: 10pt 'Helvetica Neue'; color: %@; } \
83 p { padding-top: 30px; } \
84 h1 { padding-top: 30px; } \
85 .name { font-size: 28pt; font-weight: 300; } \
86 .version { color: %@; font-size: 22pt; font-weight: 200; } \
87 .copyright { color: %@; } \
88 .description { font-weight: bold; } \
89 .licenses { color: %@; font-size: 8pt; } \
90 pre { font: 'Monaco'; } \
96 [s appendString:text];
97 NSAttributedString *as = [[NSAttributedString alloc] initWithHTML:[s dataUsingEncoding:NSUTF8StringEncoding] documentAttributes:nil];
99 self.textStorage.mutableString.string =
@"";
100 [
self.textStorage appendAttributedString:as];
114- (void)cancelOperation:(id)sender
131 if (
self = [super initWithContentRect:NSMakeRect(0, 0, 820, 500)
132 styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskFullSizeContentView
133 backing:NSBackingStoreBuffered
136 self.releasedWhenClosed = NO;
137 self.titlebarAppearsTransparent = YES;
140 NSBox *leftColumn = [NSBox new];
141 leftColumn.translatesAutoresizingMaskIntoConstraints = NO;
142 leftColumn.boxType = NSBoxCustom;
143 leftColumn.borderWidth = 0;
144 leftColumn.fillColor = NSColor.controlBackgroundColor;
148 NSImageView *icon = [NSImageView new];
149 icon.translatesAutoresizingMaskIntoConstraints = NO;
150 icon.image = NSApplication.sharedApplication.applicationIconImage;
151 [leftColumn addSubview:icon];
154 poweredByVuo.translatesAutoresizingMaskIntoConstraints = NO;
155 poweredByVuo.borderVisible = NO;
156 [leftColumn addSubview:poweredByVuo];
158 NSDictionary *views = NSDictionaryOfVariableBindings(icon, poweredByVuo);
159 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[icon(160)]-|" options:0 metrics:nil views:views]];
160 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[poweredByVuo]-|" options:0 metrics:nil views:views]];
161 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[icon(160)]-(>=0)-[poweredByVuo(120)]-|" options:0 metrics:nil views:views]];
163 [poweredByVuo release];
168 NSBox *rightColumn = [NSBox new];
169 rightColumn.translatesAutoresizingMaskIntoConstraints = NO;
170 rightColumn.boxType = NSBoxCustom;
171 rightColumn.borderWidth = 0;
172 rightColumn.fillColor = NSColor.windowBackgroundColor;
178 description.frame = NSMakeRect(0, 0, 560, 0);
179 description.translatesAutoresizingMaskIntoConstraints = NO;
180 description.drawsBackground = NO;
182 NSMutableString *s = [NSMutableString new];
184 NSString *name = NSBundle.mainBundle.infoDictionary[@"CFBundleName"];
186 name = NSProcessInfo.processInfo.processName;
187 [s appendFormat:@"<span class='name'>%@</span>", name];
189 NSString *version = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"];
191 [s appendFormat:@" <span class='version'>%@</span>", version];
193 NSString *copyright = NSBundle.mainBundle.infoDictionary[@"NSHumanReadableCopyright"];
195 [s appendFormat:@"<p class='copyright'>%@</p>", copyright];
197 NSString *desc = NSBundle.mainBundle.infoDictionary[@"description"];
199 [s appendFormat:@"<div class='description'>%@</div><br>", desc];
201 NSString *homepage = NSBundle.mainBundle.infoDictionary[@"homepageURL"];
202 NSString *documentation = NSBundle.mainBundle.infoDictionary[@"documentationURL"];
204 [s appendFormat:@"<p><a href='%@'>%@</a></p>", homepage, homepage];
206 [s appendFormat:@"<p><a href='%@'>%@</a></p>", documentation, documentation];
208 [description setText:s];
211 [rightColumn addSubview:description];
217 NSMutableString *s = [NSMutableString new];
218 [s appendString:@"<div class='licenses'>"];
219 [s appendString:[
self licenseString]];
220 [s appendString:@"</div>"];
221 [licenses setText:s];
224 NSScrollView *licensesScroller = [[NSScrollView alloc] initWithFrame:NSMakeRect(20, 20, 560, 280)];
225 licensesScroller.hasVerticalScroller = YES;
226 licensesScroller.documentView = licenses;
227 licenses.frame = NSMakeRect(0, 0, licensesScroller.contentSize.width, licensesScroller.contentSize.height);
228 [rightColumn addSubview:licensesScroller];
231 NSDictionary *views = NSDictionaryOfVariableBindings(description, licensesScroller);
232 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[description]-|" options:0 metrics:nil views:views]];
233 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[licensesScroller]-|" options:0 metrics:nil views:views]];
234 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[description][licensesScroller]-|" options:0 metrics:nil views:views]];
237 [licensesScroller release];
238 [description release];
243 self.contentView = c;
244 [c addSubview:leftColumn];
245 [c addSubview:rightColumn];
247 NSDictionary *views = NSDictionaryOfVariableBindings(leftColumn,rightColumn);
248 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[leftColumn][rightColumn]|" options:0 metrics:nil views:views]];
249 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[leftColumn]|" options:0 metrics:nil views:views]];
250 [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[rightColumn]|" options:0 metrics:nil views:views]];
253 [leftColumn release];
254 [rightColumn release];
263- (NSString *)licenseString
265 NSMutableString *s = [NSMutableString new];
268 [s appendString:@"<p>This app may include software and resources licensed under the following terms:</p>"];
272 char licensesPath[PATH_MAX+1];
277 strncpy(licensesPath, frameworkPath, PATH_MAX);
278 strncat(licensesPath,
"/Versions/" VUO_FRAMEWORK_VERSION_STRING
"/Documentation/Licenses", PATH_MAX);
282 bool foundLicenses =
false;
283 DIR *dirp = licensesPath[0] ? opendir(licensesPath) : NULL;
287 while ((dp = readdir(dirp)) != NULL)
289 if (dp->d_name[0] ==
'.')
292 char *nameWithoutExtension = strdup(dp->d_name);
293 nameWithoutExtension[strlen(nameWithoutExtension) - 4] = 0;
294 [s appendString:[NSString stringWithFormat:@"<h2>%s</h2>", nameWithoutExtension]];
295 free(nameWithoutExtension);
297 size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
298 char licensePath[pathSize];
299 strlcpy(licensePath, licensesPath, pathSize);
300 strlcat(licensePath,
"/", pathSize);
301 strlcat(licensePath, dp->d_name, pathSize);
303 [s appendString:[NSString stringWithFormat:@"<pre>%@</pre><br>",
304 [NSString stringWithContentsOfFile:[NSString stringWithUTF8String:licensePath] usedEncoding:nil error:nil]]];
306 foundLicenses =
true;
312 [s appendString:@"<p>(No license information found.)</p>"];
314 return [s autorelease];
323@property(nonatomic, strong) NSWindow *window;
331- (void)displayAboutPanel:(
id)sender
336 [_window makeKeyAndOrderFront:sender];