Merge branch 'aparajita-fonts' into 0.9.1

This commit is contained in:
Alexander Ljungberg
2011-04-02 23:32:59 -04:00
38 changed files with 4101 additions and 264 deletions
+4
View File
@@ -5,3 +5,7 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
+186 -29
View File
@@ -25,20 +25,49 @@
@import "CPView.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
var _CPFonts = {},
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
_CPFontSystemFontSize = 12,
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
/*!
@ingroup appkit
@class CPFont
The CPFont class allows control of the fonts used for displaying text anywhere on the screen. The primary method for getting a particular font is through one of the class methods that take a name and/or size as arguments, and return the appropriate CPFont.
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
The primary method for getting a particular font is through one of the class methods that take
a name and/or size as arguments, and return the appropriate CPFont.
By default the system font face/size is Arial 12px, with a fallback to sans-serif. You may
configure this at runtime in two ways:
- By sending [CPFont @link CPFont::setSystemFontFace: setSystemFontFace:@endlink] and/or [CPFont @link CPFont::setSystemFontSize: setSystemFontSize:@endlink].
- By configuring Info.plist for your application or for AppKit. You can set the font face
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
by adding a CPSystemFontSize integer item to the Info.plist.
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
The browser will use the first available font in the list. CPFont always ensures that Arial
and sans-serif are always in the generated CSS string, so there is no need to add them to
the end of your font list.
If you are using nib2cib, you should use the second method (using Info.plist),
and be sure to run nib2cib again any time you modify the CPSystemFontFace or CPSystemFontSize items.
For example, you might add this to your application's Info.plist to set the system font to Lucida Grande,
with an automatic fallback to Arial or sans-serif:
@code
<key>CPSystemFontFace</key>
<string>Lucida Grande</string>
@endcode
*/
@implementation CPFont : CPObject
{
@@ -47,78 +76,153 @@ var _CPFonts = {},
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold;
BOOL _isBold @accessors(readonly, getter=isBold);
BOOL _isItalic @accessors(readonly, getter=isItalic);
CPString _cssString;
}
+ (void)initialize
{
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFont)
_CPFontSystemFontFace = systemFont;
if (!systemFontFace)
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFontFace)
[self setSystemFontFace:systemFontFace];
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (!systemFontSize)
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (systemFontSize)
_CPFontSystemFontSize = systemFontSize;
}
/*!
Returns the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)systemFontFace
{
return _CPFontSystemFontFace;
}
/*!
Sets the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)setSystemFontFace:(CPString)aFace
{
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
}
/*!
Returns the default system font size.
*/
+ (float)systemFontSize
{
return _CPFontSystemFontSize;
}
/*!
Sets the default system font size.
*/
+ (float)setSystemFontSize:(float)size
{
if (size > 0)
_CPFontSystemFontSize = size;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO];
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
}
/*!
Returns a font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
}
/*!
Returns a bold font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, YES) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES];
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
}
/*!
Returns a bold font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
}
/*!
Returns the system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested system font
*/
+ (CPFont)systemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO];
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
}
/*!
Returns the bold system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold system font
*/
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES];
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
}
/* FIXME Font Descriptor
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
}
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
{
self = [super init];
if (self)
{
_name = aName;
_name = _CPFontNormalizedNames(aName);
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_isItalic = isItalic;
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
_CPFonts[_cssString] = self;
}
@@ -139,7 +243,7 @@ var _CPFonts = {},
/*!
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
Thus, if the longest descender extends 2 points below the baseline, descender will return 2.
Thus, if the longest descender extends 2 px below the baseline, descender will return 2.
*/
- (float)descender
{
@@ -188,12 +292,17 @@ var _CPFonts = {},
- (BOOL)isEqual:(id)anObject
{
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
return [CPString stringWithFormat:@"%@ %@", [super description], [self cssString]];
}
- (id)copy
{
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
}
- (void)_getMetrics
@@ -207,9 +316,10 @@ var _CPFonts = {},
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey";
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
CPFontIsItalicKey = @"CPFontIsItalicKey";
@implementation CPFont (CPCoding)
@@ -220,9 +330,12 @@ var CPFontNameKey = @"CPFontNameKey",
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self _initWithName:[aCoder decodeObjectForKey:CPFontNameKey]
size:[aCoder decodeFloatForKey:CPFontSizeKey]
bold:[aCoder decodeBoolForKey:CPFontIsBoldKey]];
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
size = [aCoder decodeFloatForKey:CPFontSizeKey],
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
}
/*!
@@ -234,6 +347,50 @@ var CPFontNameKey = @"CPFontNameKey",
[aCoder encodeObject:_name forKey:CPFontNameKey];
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
}
@end
// aName must be normalized
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
{
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
return properties + _CPFontConcatNameWithFallback(aName);
};
var _CPFontConcatNameWithFallback = function(aName)
{
var names = _CPFontNormalizedNameArray(aName),
fallbackFaces = _CPFontFallbackFaces.slice(0);
// Remove the fallback names used in the names passed in
for (var i = 0; i < names.length; ++i)
{
for (var j = 0; j < fallbackFaces.length; ++j)
{
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
{
fallbackFaces.splice(j, 1);
break;
}
}
if (names[i].indexOf(" ") > 0)
names[i] = '"' + names[i] + '"';
}
return names.concat(fallbackFaces).join(", ");
};
var _CPFontNormalizedNameArray = function(aName)
{
var names = aName.split(",");
for (var i = 0; i < names.length; ++i)
names[i] = names[i].replace(_CPFontStripRegExp, "");
return names;
};
+28
View File
@@ -26,6 +26,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPNumber _selectedIndex;
CPTabViewType _type;
CPFont _font;
id _delegate;
unsigned _delegateSelectors;
@@ -267,6 +268,27 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
return [_items objectAtIndex:_selectedIndex];
}
// Modifying the font
/*!
Returns the font for tab label text.
*/
- (CPFont)font
{
return _font;
}
/*!
Sets the font for tab label text to font.
*/
- (void)setFont:(CPFont)font
{
if ([_font isEqual:font])
return;
_font = font;
[_tabs setFont:_font];
}
//
/*!
Sets the tab view type.
@@ -415,6 +437,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var CPTabViewItemsKey = "CPTabViewItemsKey",
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
CPTabViewTypeKey = "CPTabViewTypeKey",
CPTabViewFontKey = "CPTabViewFontKey",
CPTabViewDelegateKey = "CPTabViewDelegateKey";
@implementation CPTabView (CPCoding)
@@ -425,12 +448,16 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
[self _init];
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
[_tabs setFont:_font];
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
[self _updateItems];
[self _repositionTabs];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
@@ -450,6 +477,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
+12
View File
@@ -0,0 +1,12 @@
var OS = require("os");
exports.fontinfo = function(name, size)
{
var p = OS.popen(["fontinfo", "-n", name, size || 12]);
if (p.wait() === 0)
return JSON.parse(p.stdout.read());
else
return null;
}
+4 -9
View File
@@ -166,16 +166,11 @@ var stream;
GLOBAL(CPLogColorize) = function(aString, aLevel)
{
if (stream)
{
// Try to determine if a colorizing stanza is already open, they can't be nested
if (/^.*\x00\w+\([^\x00]*$/.test(aString))
return aString;
else
return "\0" + (levelColorMap[aLevel] || "info") + "(" + aString + "\0)";
}
else
// Try to determine if a colorizing stanza is already open, they can't be nested
if (/^.*\x00\w+\([^\x00]*$/.test(aString))
return aString;
else
return "\0" + (levelColorMap[aLevel] || "info") + "(" + aString + "\0)";
}
GLOBAL(CPLogPrint) = function(aString, aLevel, aTitle, aFormatter)
+46 -6
View File
@@ -4,7 +4,7 @@
{
CPFont _systemFont;
CPFont _boldSystemFont;
CPFont _customFont;
CPFont _boldCustomFont;
}
@@ -13,29 +13,33 @@
{
_systemFont = [CPFont systemFontOfSize:15];
_boldSystemFont = [CPFont boldSystemFontOfSize:15];
_customFont = [CPFont fontWithName:@"Marker Felt, Lucida Grande, Helvetica" size:30];
_boldCustomFont = [CPFont boldFontWithName:@"Helvetica" size:30];
}
- (void)testSystemFontCSSString
{
[self assert:[_systemFont cssString] equals:@"15px Arial, sans-serif"];
var font = _CPFontConcatNameWithFallback([CPFont systemFontFace]);
[self assert:[_systemFont cssString] equals:@"15px " + font];
}
- (void)testBoldSystemFontCSSString
{
[self assert:[_boldSystemFont cssString] equals:@"bold 15px Arial, sans-serif"];
var font = _CPFontConcatNameWithFallback([CPFont systemFontFace]);
[self assert:[_boldSystemFont cssString] equals:@"bold 15px " + font];
}
- (void)testCustomFontCSSString
{
[self assert:[_customFont cssString] equals:@"30px \"Marker Felt\", \"Lucida Grande\", \"Helvetica\", Arial, sans-serif"];
[self assert:[_customFont cssString] equals:@"30px \"Marker Felt\", \"Lucida Grande\", Helvetica, Arial, sans-serif"];
}
- (void)testBoldCustomFontCSSString
{
[self assert:[_boldCustomFont cssString] equals:@"bold 30px \"Helvetica\", Arial, sans-serif"];
[self assert:[_boldCustomFont cssString] equals:@"bold 30px Helvetica, Arial, sans-serif"];
}
- (void)testIsEqual
@@ -48,3 +52,39 @@
}
@end
var _CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
var _CPFontConcatNameWithFallback = function(aName)
{
var names = _CPFontNormalizedNameArray(aName),
fallbackFaces = ["Arial", "sans-serif"];
// Remove the fallback names used in the names passed in
for (var i = 0; i < names.length; ++i)
{
for (var j = 0; j < fallbackFaces.length; ++j)
{
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
{
fallbackFaces.splice(j, 1);
break;
}
}
if (names[i].indexOf(" ") > 0)
names[i] = '"' + names[i] + '"';
}
return names.concat(fallbackFaces).join(", ");
};
var _CPFontNormalizedNameArray = function(aName)
{
var names = aName.split(",");
for (var i = 0; i < names.length; ++i)
names[i] = names[i].replace(_CPFontStripRegExp, "");
return names;
};
@@ -0,0 +1,120 @@
/*
* AppController.j
* test
*
* Created by aparajita on March 9, 2011.
* Copyright 2011, Victory-Heart Productions All rights reserved.
*/
@import <Foundation/CPObject.j>
var fontLabelField = nil,
defaultFontLabelText = @"";
@implementation AppController : CPObject
{
CPWindow theWindow; //this "outlet" is connected automatically by the Cib
CPTextField label1;
CPTextField fontLabel;
CPTableView theTableView;
CPRadio radio1;
CPRadio radio2;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
// This is called when the application is done loading.
}
- (void)awakeFromCib
{
// This is called when the cib is done loading.
// You can implement this method on any object instantiated from a Cib.
// It's a useful hook for setting up current UI values, and other things.
// In this case, we want the window from Cib to become our full browser window
[theWindow setFullPlatformWindow:NO];
fontLabelField = fontLabel;
defaultFontLabelText = [fontLabelField stringValue];
var font = [CPFont fontWithName:@"Palatino, Cambria" size:14];
[radio1 setFont:font];
[radio2 setFont:font];
}
- (int)numberOfRowsInTableView:(id)aTableView
{
return 7;
}
- (id)tableView:(id)tableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRow
{
return ["one", "two", "three"][parseInt([aColumn identifier], 10)];
}
@end
@implementation CPView (testApp)
- (void)doMouseEntered
{
[fontLabelField setStringValue:@"View font: " + [[self font] cssString]];
}
- (void)doMouseExited
{
[fontLabelField setStringValue:defaultFontLabelText];
}
@end
@implementation CPControl (testApp)
- (void)awakeFromCib
{
[super awakeFromCib];
var size = [self frameSize],
lineHeight = [[self font] defaultLineHeightForFont],
inset = [self hasThemeAttribute:@"content-inset"] ? [self currentValueForThemeAttribute:@"content-inset"] : nil,
minSize = [self hasThemeAttribute:@"min-size"] ? [self currentValueForThemeAttribute:@"min-size"] : nil,
height = lineHeight + (inset ? inset.top + inset.bottom : 0);
if (minSize)
height = MAX(height, minSize.height);
[self setFrameSize:CGSizeMake(size.width, MAX(size.height, height))];
}
- (void)mouseEntered:(CPEvent)anEvent
{
[self doMouseEntered];
}
- (void)mouseExited:(CPEvent)anEvent
{
[self doMouseExited];
}
@end
@implementation CPTabView (testApp)
- (void)mouseEntered:(CPEvent)anEvent
{
[_tabs doMouseEntered];
}
- (void)mouseExited:(CPEvent)anEvent
{
[_tabs doMouseExited];
}
@end
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Main cib file base name</key>
<string>MainMenu.cib</string>
<key>CPBundleName</key>
<string>FontEnhancementTest</string>
<key>CPSystemFontFace</key>
<string>Lucida Grande</string>
<key>CPSystemFontSize</key>
<string>12</string>
</dict>
</plist>
+94
View File
@@ -0,0 +1,94 @@
/*
* Jakefile
* test
*
* Created by aparajita on March 9, 2011.
* Copyright 2011, Victory-Heart Productions All rights reserved.
*/
var ENV = require("system").env,
FILE = require("file"),
JAKE = require("jake"),
task = JAKE.task,
FileList = JAKE.FileList,
app = require("cappuccino/jake").app,
configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug",
OS = require("os");
app ("test", function(task)
{
task.setBuildIntermediatesPath(FILE.join("Build", "test.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("test");
task.setIdentifier("com.aparajitaworld.test");
task.setVersion("1.0");
task.setAuthor("Victory-Heart Productions");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("test");
task.setSources((new FileList("**/*.j")).exclude(FILE.join("Build", "**")));
task.setResources(new FileList("Resources/**"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
task.setNib2CibFlags("-R Resources/");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
});
task ("default", ["test"], function()
{
printResults(configuration);
});
task ("build", ["default"]);
task ("debug", function()
{
ENV["CONFIGURATION"] = "Debug";
JAKE.subjake(["."], "build", ENV);
});
task ("release", function()
{
ENV["CONFIGURATION"] = "Release";
JAKE.subjake(["."], "build", ENV);
});
task ("run", ["debug"], function()
{
OS.system(["open", FILE.join("Build", "Debug", "test", "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", FILE.join("Build", "Release", "test", "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Deployment", "test"));
OS.system(["press", "-f", FILE.join("Build", "Release", "test"), FILE.join("Build", "Deployment", "test")]);
printResults("Deployment")
});
task ("desktop", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Desktop", "test"));
require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "test"), FILE.join("Build", "Desktop", "test", "test.app"));
printResults("Desktop")
});
task ("run-desktop", ["desktop"], function()
{
OS.system([FILE.join("Build", "Desktop", "test", "test.app", "Contents", "MacOS", "NativeHost"), "-i"]);
});
function printResults(configuration)
{
print("----------------------------");
print(configuration+" app built at path: "+FILE.join("Build", configuration, "test"));
print("----------------------------");
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,104 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index-debug.html
test
Created by aparajita on March 9, 2011.
Copyright 2011, Victory-Heart Productions All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<link href='http://fonts.googleapis.com/css?family=Ubuntu,Cabin' rel='stylesheet' type='text/css' />
<title>FontEnhancementTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
</script>
<script type="text/javascript" src="Frameworks/Debug/Objective-J/Objective-J.js" charset="UTF-8"></script>
<script type="text/javascript">
objj_msgSend_reset();
// DEBUG OPTIONS:
// Uncomment to enable printing of backtraces on exceptions:
//objj_msgSend_decorate(objj_backtrace_decorator);
// Uncomment to supress exceptions that take place inside a message
//objj_msgSend_decorate(objj_supress_exceptions_decorator)
// Uncomment to enable runtime type checking:
//objj_msgSend_decorate(objj_typecheck_decorator);
// Uncomment (along with both above) to print backtraces on type check errors:
//objj_typecheck_prints_backtrace = true;
// Uncomment to disable the default logger (CPLogConsole if window.console exists, CPLogPopup otherwise):
//CPLogUnregister(CPLogDefault);
// Uncomment to enable a specific logger:
//CPLogRegister(CPLogConsole);
//CPLogRegister(CPLogPopup);
</script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading test...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
@@ -0,0 +1,78 @@
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<!--
index.html
test
Created by aparajita on March 9, 2011.
Copyright 2011, Victory-Heart Productions All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="apple-touch-icon" href="Resources/icon.png" />
<link rel="apple-touch-startup-image" href="Resources/default.png" />
<link href='http://fonts.googleapis.com/css?family=Ubuntu,Cabin' rel='stylesheet' type='text/css' />
<title>FontEnhancementTest</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
</script>
<script type="text/javascript" src="Frameworks/Objective-J/Objective-J.js" charset="UTF-8"></script>
<style type="text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="cappuccino-body">
<div id="loadingcontainer" style="background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type="text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading test...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* test
*
* Created by aparajita on March 9, 2011.
* Copyright 2011, Victory-Heart Productions All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+4 -2
View File
@@ -1,5 +1,7 @@
require("../common.jake");
// nib2cib has to come before capp since capp uses nib2cib
subtasks(["nib2cib", "capp", "NativeHost"], ["build"/*, "clean", "clobber"*/]);
// nib2cib uses fontinfo and capp uses nib2cib
subtasks(["fontinfo", "nib2cib", "capp", "NativeHost"], ["build"/*, "clean", "clobber"*/]);
subtasks(["fontinfo"], ["clean", "clobber"]);
+1
View File
@@ -0,0 +1 @@
build/
+40
View File
@@ -0,0 +1,40 @@
require ("../../common.jake");
var OS = require("os"),
task = require("jake").task;
task ("build", function()
{
if (executableExists("xcodebuild"))
{
var args = "-alltargets -configuration " + $CONFIGURATION;
if (FILE.exists(FILE.join("/", "Developer", "SDKs", "MacOSX10.5.sdk")))
args = "-sdk macosx10.5 " + args;
else
args = "-sdk macosx " + args;
if (OS.system("xcodebuild " + args))
OS.exit(1);
}
else
{
print("Building fontinfo requires Xcode.");
}
});
task ("clean", function()
{
if (OS.system("xcodebuild clean"))
OS.exit(1);
});
task ("clobber", function()
{
if (OS.system("xcodebuild clean"))
OS.exit(1);
});
task ("default", ["build"]);
+51
View File
@@ -0,0 +1,51 @@
NAME
fontinfo -- retrieve information about a font
SYNOPSIS
fontinfo [-n] font [size [string]]
DESCRIPTION
fontinfo is a tiny utility that returns information about a font.
The font name must be a full PostScript name, not a display name. So you would use something
like "LucidaGrande-Bold", not "Lucida Grande Bold". The size can be any floating point number
greater than zero. If no size is given, it defaults to 12.
If the -n option is passed, the output will not be terminated with a linefeed.
If the string argument is passed, its width in the given font is measured and returned.
EXIT STATUS
fontinfo exits with a return status of zero if there are no errors.
fontinfo exits with a return status of 1 if any arguments are invalid, or a status of 2 if the font
cannot be found.
OUTPUT
fontinfo outputs a stringified JSON object with the following structure:
{
familyName:<string>,
bold:<boolean>,
italic:<boolean>,
ascender:<float>,
descender:<float>,
line-height:<float>
width:<float>
}
If -n is not passed, the JSON is terminated with a linefeed. The fields of the object are as follows:
familyName: The display name of the font's family
bold: Whether the font's stylistic traits are considered bold
italic: Whether the font's stylistic traits are considered italic
ascender: The offset from the baseline in points (not pixels!) of the longest ascender of the given font at
the given size.
descender: The negative offset from the baseline in points (not pixels!)
of the longest descender of the given font at the given size.
lineHeight: The height in points (not pixels!) of the largest glyph in the given font at the given size.
Note that glyphs include diacritical marks that may appear above and below the largest ascender
and descender, so the line height will almost always be greater than ascender + descender.
width: If a string is passed, the width in pixels of the string in the given font, otherwise zero
AUTHORS
Aparajita Fishman, Victory-Heart Productions
http://www.aparajita.com
+114
View File
@@ -0,0 +1,114 @@
/*
font_info
Copyright 2010 Aparajita Fishman
*/
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#define resultFormat @"{\"familyName\":\"%@\", \"bold\":%@, \"italic\":%@, \"ascender\":%g, \"descender\":%g, \"lineHeight\":%g, \"width\":%g}"
enum {
kErrInvalidArguments = 1,
kErrInvalidFontName
};
int main(int argc, const char* argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int exitCode = 0;
NSString* stringToMeasure = nil;
// usage: fontinfo [-n] face [size [string]]
if (argc >= 2)
{
BOOL appendLineFeed = YES;
int nextArgument = 1;
if (argv[1][0] == '-')
{
if (argv[1][1] == 'n')
{
appendLineFeed = NO;
++nextArgument;
}
else
exitCode = kErrInvalidArguments;
}
if (exitCode == 0)
{
CGFloat fontSize = 12;
NSString* fontName = [NSString stringWithUTF8String:argv[nextArgument++]];
if (argc > nextArgument)
fontSize = atof(argv[nextArgument++]);
if (fontSize > 0.0)
{
NSFont* font = [NSFont fontWithName:fontName size:fontSize];
if (font)
{
if (argc > nextArgument)
stringToMeasure = [NSString stringWithUTF8String:argv[nextArgument]];
NSString* familyName = [font familyName];
NSFontDescriptor* descriptor = [font fontDescriptor];
NSFontSymbolicTraits traits = [descriptor symbolicTraits];
BOOL isBold = traits & NSFontBoldTrait;
BOOL isItalic = traits & NSFontItalicTrait;
CGFloat ascender = [font ascender];
CGFloat descender = [font descender];
NSLayoutManager* layout = [NSLayoutManager new];
CGFloat lineHeight = [layout defaultLineHeightForFont:font];
[layout release];
CGFloat width = 0.0;
if (stringToMeasure)
{
NSDictionary* attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
NSAttributedString* attrString = [[NSAttributedString alloc] initWithString:stringToMeasure attributes:attributes];
if (attrString)
width = [attrString size].width;
[attrString release];
}
NSMutableString* result = [NSMutableString stringWithFormat:resultFormat,
familyName,
isBold ? @"true" : @"false", isItalic ? @"true" : @"false",
ascender, descender, lineHeight,
width];
if (appendLineFeed)
[result appendString:@"\n"];
printf("%s", [result UTF8String]);
}
else
{
exitCode = kErrInvalidFontName;
}
}
else
{
exitCode = kErrInvalidArguments;
}
}
}
else
{
exitCode = kErrInvalidArguments;
}
[pool drain];
return exitCode;
}
@@ -0,0 +1,223 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 45;
objects = {
/* Begin PBXBuildFile section */
E1C392BC133D513B0092D7CA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1C392BB133D513B0092D7CA /* Cocoa.framework */; };
E1D3CFAA12AFFB7F00CBB79E /* fontinfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* fontinfo.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
08FB7796FE84155DC02AAC07 /* fontinfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fontinfo.m; sourceTree = "<group>"; };
08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
32A70AAB03705E1F00C91783 /* fontinfo_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fontinfo_Prefix.pch; sourceTree = "<group>"; };
E11C89CC1277CECE0012609B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
E18587D81279B93100FB6A47 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
E1C392BB133D513B0092D7CA /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
E1E20D0B12B09283005A6A64 /* fontinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fontinfo; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
E1D3CF6912AFEE3800CBB79E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E1C392BC133D513B0092D7CA /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
08FB7794FE84155DC02AAC07 /* font_info */ = {
isa = PBXGroup;
children = (
08FB7795FE84155DC02AAC07 /* Source */,
E18587DD1279B93600FB6A47 /* Documentation */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
1AB674ADFE9D54B511CA2CBB /* Products */,
);
name = font_info;
sourceTree = "<group>";
};
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
32A70AAB03705E1F00C91783 /* fontinfo_Prefix.pch */,
08FB7796FE84155DC02AAC07 /* fontinfo.m */,
);
name = Source;
sourceTree = "<group>";
};
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
08FB779EFE84155DC02AAC07 /* Foundation.framework */,
E11C89CC1277CECE0012609B /* AppKit.framework */,
E1C392BB133D513B0092D7CA /* Cocoa.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
1AB674ADFE9D54B511CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
E1E20D0B12B09283005A6A64 /* fontinfo */,
);
name = Products;
sourceTree = "<group>";
};
E18587DD1279B93600FB6A47 /* Documentation */ = {
isa = PBXGroup;
children = (
E18587D81279B93100FB6A47 /* README */,
);
name = Documentation;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
E1D3CF6A12AFEE3800CBB79E /* fontinfo */ = {
isa = PBXNativeTarget;
buildConfigurationList = E1D3CF6F12AFEE3B00CBB79E /* Build configuration list for PBXNativeTarget "fontinfo" */;
buildPhases = (
E1D3CF6812AFEE3800CBB79E /* Sources */,
E1D3CF6912AFEE3800CBB79E /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = fontinfo;
productName = font_info;
productReference = E1E20D0B12B09283005A6A64 /* fontinfo */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "fontinfo" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
);
mainGroup = 08FB7794FE84155DC02AAC07 /* font_info */;
projectDirPath = "";
projectRoot = "";
targets = (
E1D3CF6A12AFEE3800CBB79E /* fontinfo */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
E1D3CF6812AFEE3800CBB79E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E1D3CFAA12AFFB7F00CBB79E /* fontinfo.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB927908733DD40010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
CONFIGURATION_TEMP_DIR = "$(CAPP_BUILD)";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = fontinfo_Prefix.pch;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
OBJROOT = "$(CAPP_BUILD)";
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"-framework",
Foundation,
"-framework",
AppKit,
);
PREBINDING = NO;
PRODUCT_NAME = fontinfo;
SDKROOT = macosx10.5;
SYMROOT = "$(CAPP_BUILD)/Debug/CommonJS/cappuccino/bin";
};
name = Debug;
};
1DEB927A08733DD40010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(NATIVE_ARCH_ACTUAL)";
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
CONFIGURATION_TEMP_DIR = "$(CAPP_BUILD)";
DEPLOYMENT_LOCATION = NO;
DEPLOYMENT_POSTPROCESSING = NO;
DSTROOT = "/tmp/$(PROJECT_NAME).dst";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = "";
OBJROOT = "$(CAPP_BUILD)";
ONLY_ACTIVE_ARCH = NO;
PREBINDING = NO;
PRODUCT_NAME = fontinfo;
SDKROOT = macosx10.5;
SYMROOT = "$(CAPP_BUILD)/Release/CommonJS/cappuccino/bin";
};
name = Release;
};
E1D3CF6D12AFEE3900CBB79E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Debug;
};
E1D3CF6E12AFEE3900CBB79E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
MACOSX_DEPLOYMENT_TARGET = 10.5;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "fontinfo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB927908733DD40010E9CD /* Debug */,
1DEB927A08733DD40010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E1D3CF6F12AFEE3B00CBB79E /* Build configuration list for PBXNativeTarget "fontinfo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E1D3CF6D12AFEE3900CBB79E /* Debug */,
E1D3CF6E12AFEE3900CBB79E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
}
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:fontinfo.xcodeproj">
</FileRef>
</Workspace>
+8
View File
@@ -0,0 +1,8 @@
//
// Prefix header for all source files of the 'font_info' target in the 'font_info' project.
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#endif
+75 -13
View File
@@ -23,25 +23,25 @@
@import "Converter.j"
@implementation Converter (Mac)
- (void)convertedDataFromMacData:(CPData)data resourcesPath:(CPString)aResourcesPath
{
// Unarchive the NS data
var unarchiver = [[Nib2CibKeyedUnarchiver alloc] initForReadingWithData:data resourcesPath:aResourcesPath],
objectData = [unarchiver decodeObjectForKey:@"IB.objectdata"];
// Perform a bit of post-processing on views since all CP views are flipped.
// It's better to do this here (instead of say, in NSView::initWithCoder:),
// because at this point all the objects an mappings are stabilized.
var objects = [unarchiver allObjects],
objectData = [unarchiver decodeObjectForKey:@"IB.objectdata"],
objects = [unarchiver allObjects],
count = [objects count];
// Perform a bit of post-processing on fonts and views since all CP views are flipped.
// It's better to do this here (instead of say, in NSView::initWithCoder:),
// because at this point all the objects and mappings are stabilized.
while (count--)
{
var object = objects[count];
[self replaceFontForObject:object];
if (![object isKindOfClass:[CPView class]])
continue;
@@ -76,20 +76,82 @@
var convertedData = [CPData data],
archiver = [[CPKeyedArchiver alloc] initForWritingWithMutableData:convertedData];
[archiver setDelegate:self];
[archiver encodeObject:objectData forKey:@"CPCibObjectDataKey"];
[archiver finishEncoding];
return convertedData;
}
// For some reason, occasionally an attempt is made to archive NSMatrix. That will fail, so prevent it here.
- (id)archiver:(CPKeyedArchiver)archiver willEncodeObject:(id)object
- (void)replaceFontForObject:(id)object
{
if ([object isKindOfClass:[NSMatrix class]])
return nil;
if ([object respondsToSelector:@selector(font)] &&
[object respondsToSelector:@selector(setFont:)])
{
var nibFont = [object font];
if (nibFont)
[self replaceFont:nibFont forObject:object];
}
else if ([object isKindOfClass:[CPView class]])
{
/*
Determine if a view is actually a container for radio buttons.
They have to be manually iterated over because they are not
part of the top level object data.
*/
var subviews = [object subviews],
count = [subviews count];
if (count && [subviews[0] isKindOfClass:[CPRadio class]])
{
while (count--)
{
var radio = subviews[count];
[self replaceFont:[radio font] forObject:radio];
}
}
}
}
- (void)replaceFont:(CPFont)nibFont forObject:(id)object
{
var cibFont = nil;
if ([object respondsToSelector:@selector(cibFontForNibFont)])
cibFont = [object cibFontForNibFont];
else
return object;
cibFont = [NSFont cibFontForNibFont:[object font]];
if (!cibFont || ![cibFont isEqual:nibFont])
{
var source = "";
// nil cibFont means try to use theme font
if (!cibFont)
{
var bold = [nibFont isBold];
cibFont = [theme valueForAttributeWithName:@"font" inState:[object themeState] forClass:[object class]];
// Substitute legacy theme fonts for the current system font
if (!cibFont || [cibFont familyName] === CPFontDefaultSystemFontFace)
{
var size = [cibFont size] || CPFontDefaultSystemFontSize,
bold = cibFont ? [cibFont isBold] : bold;
if (size === CPFontDefaultSystemFontSize)
size = [CPFont systemFontSize];
cibFont = bold ? [CPFont boldSystemFontOfSize:size] : [CPFont systemFontOfSize:size];
source = " (from theme)"
}
}
[object setFont:cibFont];
CPLog.debug("%s: substituted <%s>%s for <%fpx %s>", [object className], cibFont ? [cibFont cssString] : "theme default", source, [nibFont size], [nibFont familyName]);
}
}
@end
+98 -69
View File
@@ -18,113 +18,142 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPData.j>
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import <BlendKit/BlendKit.j>
var FILE = require("file"),
OS = require("os");
OS = require("os"),
SharedConverter = nil;
NibFormatUndetermined = 0,
NibFormatMac = 1,
NibFormatIPhone = 2;
NibFormatUndetermined = 0,
NibFormatMac = 1,
NibFormatIPhone = 2;
ConverterConversionException = @"ConverterConversionException";
ConverterModeLegacy = 0;
ConverterModeNew = 1;
ConverterConversionException = @"ConverterConversionException";
@implementation Converter : CPObject
{
NibFormat format @accessors;
CPString inputPath @accessors;
CPString outputPath @accessors;
CPString resourcesPath @accessors;
CPString inputPath @accessors(readonly);
CPString outputPath @accessors;
CPString resourcesPath @accessors;
NibFormat format @accessors(readonly);
CPTheme theme @accessors(readonly);
}
- (id)init
+ (Converter)sharedConverter
{
if (!SharedConverter)
SharedConverter = [[Converter alloc] init];
return SharedConverter;
}
- (id)initWithInputPath:(CPString)aPath format:(NibFormat)nibFormat theme:(CPTheme)aTheme
{
self = [super init];
if (self)
[self setFormat:NibFormatUndetermined];
{
inputPath = aPath;
format = nibFormat;
theme = aTheme;
}
return self;
}
- (void)convert
{
try
if ([resourcesPath length] && !FILE.isReadable(resourcesPath))
[CPException raise:ConverterConversionException reason:@"Could not read Resources at path \"" + resourcesPath + "\""];
var inferredFormat = format;
if (inferredFormat === NibFormatUndetermined)
{
if ([resourcesPath length] && !FILE.isReadable(resourcesPath))
[CPException raise:ConverterConversionException reason:@"Could not read Resources at path \"" + resourcesPath + "\""];
// Assume its a Mac file.
inferredFormat = NibFormatMac;
var inferredFormat = format;
if (inferredFormat === NibFormatUndetermined)
{
// Assume its a Mac file.
inferredFormat = NibFormatMac;
// Some .xibs are iPhone nibs, check the actual contents in this case.
if (FILE.extension(inputPath) !== ".nib" && FILE.isFile(inputPath) &&
FILE.read(inputPath, { charset:"UTF-8" }).indexOf("<archive type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\"") !== -1)
inferredFormat = NibFormatIPhone;
if (inferredFormat === NibFormatMac)
CPLog.info("Auto-detected Cocoa Nib or Xib File");
else
CPLog.info("Auto-detected CocoaTouch Xib File");
}
var nibData = [self CPCompliantNibDataAtFilePath:inputPath];
// Some .xibs are iPhone nibs, check the actual contents in this case.
if (FILE.extension(inputPath) !== ".nib" && FILE.isFile(inputPath) &&
FILE.read(inputPath, { charset:"UTF-8" }).indexOf("<archive type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\"") !== -1)
inferredFormat = NibFormatIPhone;
if (inferredFormat === NibFormatMac)
var convertedData = [self convertedDataFromMacData:nibData resourcesPath:resourcesPath];
CPLog.info("Auto-detected Cocoa Nib or Xib File");
else
[CPException raise:ConverterConversionException reason:@"nib2cib does not understand this nib format."];
if (![outputPath length])
outputPath = inputPath.substr(0, inputPath.length - FILE.extension(inputPath).length) + ".cib";
FILE.write(outputPath, [convertedData rawString], { charset:"UTF-8" });
}
catch(anException)
{
CPLog.fatal(anException);
CPLog.info("Auto-detected CocoaTouch Xib File");
}
var nibData = [self CPCompliantNibDataAtFilePath:inputPath];
if (inferredFormat === NibFormatMac)
var convertedData = [self convertedDataFromMacData:nibData resourcesPath:resourcesPath];
else
[CPException raise:ConverterConversionException reason:@"nib2cib does not understand this nib format."];
if (![outputPath length])
outputPath = inputPath.substr(0, inputPath.length - FILE.extension(inputPath).length) + ".cib";
FILE.write(outputPath, [convertedData rawString], { charset:"UTF-8" });
CPLog.info(CPLogColorize("Conversion successful", "warn"));
}
- (CPData)CPCompliantNibDataAtFilePath:(CPString)aFilePath
{
// Compile xib or nib to make sure we have a non-new format nib.
var temporaryNibFilePath = FILE.join("/tmp", FILE.basename(aFilePath) + ".tmp.nib");
CPLog.info("Converting Xib file to plist...");
if (OS.popen(["/usr/bin/ibtool", aFilePath, "--compile", temporaryNibFilePath]).wait() === 1)
throw "Could not compile file at " + aFilePath;
var temporaryNibFilePath = "",
temporaryPlistFilePath = "";
// Convert from binary plist to XML plist
var temporaryPlistFilePath = FILE.join("/tmp", FILE.basename(aFilePath) + ".tmp.plist");
try
{
// Compile xib or nib to make sure we have a non-new format nib.
temporaryNibFilePath = FILE.join("/tmp", FILE.basename(aFilePath) + ".tmp.nib");
if (OS.popen(["/usr/bin/plutil", "-convert", "xml1", temporaryNibFilePath, "-o", temporaryPlistFilePath]).wait() === 1)
throw "Could not convert to xml plist for file at " + aFilePath;
if (OS.popen(["/usr/bin/ibtool", aFilePath, "--compile", temporaryNibFilePath]).wait() === 1)
[CPException raise:ConverterConversionException reason:@"Could not compile file: " + aFilePath];
if (!FILE.isReadable(temporaryPlistFilePath))
[CPException raise:ConverterConversionException reason:@"Unable to convert nib file."];
// Convert from binary plist to XML plist
var temporaryPlistFilePath = FILE.join("/tmp", FILE.basename(aFilePath) + ".tmp.plist");
var plistContents = FILE.read(temporaryPlistFilePath, { charset:"UTF-8" });
if (OS.popen(["/usr/bin/plutil", "-convert", "xml1", temporaryNibFilePath, "-o", temporaryPlistFilePath]).wait() === 1)
[CPException raise:ConverterConversionException reason:@"Could not convert to xml plist for file: " + aFilePath];
// Minor NS keyed archive to CP keyed archive conversion.
// Use Java directly because rhino's string.replace is *so slow*. 4 seconds vs. 1 millisecond.
// plistContents = plistContents.replace(/\<key\>\s*CF\$UID\s*\<\/key\>/g, "<key>CP$UID</key>");
if (system.engine === "rhino")
plistContents = String(java.lang.String(plistContents).replaceAll("\\<key\\>\\s*CF\\$UID\\s*\\<\/key\\>", "<key>CP\\$UID</key>"));
else
plistContents = plistContents.replace(/\<key\>\s*CF\$UID\s*\<\/key\>/g, "<key>CP$UID</key>");
if (!FILE.isReadable(temporaryPlistFilePath))
[CPException raise:ConverterConversionException reason:@"Unable to convert nib file."];
plistContents = plistContents.replace(/<string>[\u0000-\u0008\u000B\u000C\u000E-\u001F]<\/string>/g, function(c) {
CPLog.warn("Warning: Converting character 0x"+c.charCodeAt(8).toString(16)+" to base64 representation");
return "<string type=\"base64\">"+CFData.encodeBase64String(c.charAt(8))+"</string>";
});
var plistContents = FILE.read(temporaryPlistFilePath, { charset:"UTF-8" });
// Minor NS keyed archive to CP keyed archive conversion.
// Use Java directly because rhino's string.replace is *so slow*. 4 seconds vs. 1 millisecond.
// plistContents = plistContents.replace(/\<key\>\s*CF\$UID\s*\<\/key\>/g, "<key>CP$UID</key>");
if (system.engine === "rhino")
plistContents = String(java.lang.String(plistContents).replaceAll("\\<key\\>\\s*CF\\$UID\\s*\\<\/key\\>", "<key>CP\\$UID</key>"));
else
plistContents = plistContents.replace(/\<key\>\s*CF\$UID\s*\<\/key\>/g, "<key>CP$UID</key>");
plistContents = plistContents.replace(/<string>[\u0000-\u0008\u000B\u000C\u000E-\u001F]<\/string>/g, function(c)
{
CPLog.warn("Warning: converting character 0x" + c.charCodeAt(8).toString(16) + " to base64 representation");
return "<string type=\"base64\">"+CFData.encodeBase64String(c.charAt(8))+"</string>";
});
}
finally
{
if (temporaryNibFilePath !== "" && FILE.isWritable(temporaryNibFilePath))
FILE.remove(temporaryNibFilePath);
if (temporaryPlistFilePath !== "" && FILE.isWritable(temporaryPlistFilePath))
FILE.remove(temporaryPlistFilePath);
}
return [CPData dataWithRawString:plistContents];
}
+1 -1
View File
@@ -83,7 +83,7 @@ function CP_NSMapClassName(aClassName)
if (CPClassFromString(mappedClassName))
{
CPLog.info("Mapping " + aClassName + " to " + mappedClassName);
CPLog.debug("NSAppKit: mapping " + aClassName + " to " + mappedClassName);
return mappedClassName;
}
+4 -3
View File
@@ -32,6 +32,7 @@
var _CPButtonBezelStyleHeights = {};
_CPButtonBezelStyleHeights[CPRoundedBezelStyle] = 18;
_CPButtonBezelStyleHeights[CPTexturedRoundedBezelStyle] = 20;
_CPButtonBezelStyleHeights[CPHUDBezelStyle] = 20;
@@ -117,18 +118,18 @@ var NSButtonIsBorderedMask = 0x00800000,
case CPHelpButtonBezelStyle:
case CPCircularBezelStyle:
case CPDisclosureBezelStyle:
CPLog.warn("Unsupported bezel style: " + _bezelStyle);
CPLog.warn("NSButton [%s]: unsupported bezel style: %d", _title == null ? "<no title>" : '"' + _title + '"', _bezelStyle);
_bezelStyle = CPHUDBezelStyle;
break;
// error:
default:
CPLog.error("Unknown bezel style: " + _bezelStyle);
CPLog.warn("NSButton [%s]: unknown bezel style: %d", _title == null ? "<no title>" : '"' + _title + '"', _bezelStyle);
_bezelStyle = CPHUDBezelStyle;
}
if ([cell isBordered])
{
CPLog.info("Adjusting CPButton height from " +_frame.size.height+ " / " + _bounds.size.height+" to " + CPButtonDefaultHeight);
CPLog.debug("NSButton [%s]: adjusting height from %d to %d", _title == null ? "<no title>" : '"' + _title + '"', _frame.size.height, CPButtonDefaultHeight);
_frame.size.height = CPButtonDefaultHeight;
_frame.origin.y += 4.0;
_bounds.size.height = CPButtonDefaultHeight;
+1 -1
View File
@@ -119,7 +119,7 @@ var NSUnknownColorSpaceModel = -1,
}
break;
default:
CPLog(@"-[%@ %s] unknown color space %d", isa, _cmd, colorSpace);
CPLog.warn(@"-[%@ %s] unknown color space %d", isa, _cmd, colorSpace);
result = [CPColor blackColor];
break;
}
+2 -2
View File
@@ -41,13 +41,13 @@ var FILE = require("file");
var size = CGSizeMakeZero();
if (![[aCoder resourcesPath] length])
CPLog.warn("*** WARNING: Resources found in nib, but no resources path specified with -R option.");
CPLog.warn("Resources found in nib, but no resources path specified with -R option.");
else
{
var resourcePath = [aCoder resourcePathForName:_resourceName];
if (!resourcePath)
CPLog.warn("*** WARNING: Resource named " + _resourceName + " not found in supplied resources path.");
CPLog.warn("Resource named " + _resourceName + " not found in the supplied resources path.");
else
size = imageSize(FILE.join(FILE.cwd(), resourcePath));
+35 -14
View File
@@ -22,35 +22,56 @@
@import <AppKit/CPFont.j>
var OS = require("os"),
fontinfo = require("cappuccino/fontinfo").fontinfo;
var IBDefaultFontFace = @"Lucida Grande",
IBDefaultFontSize = 13.0;
@implementation CPFont (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
var isBold = NO,
fontName = [aCoder decodeObjectForKey:@"NSName"],
size = [aCoder decodeDoubleForKey:@"NSSize"];
var name = [aCoder decodeObjectForKey:@"NSName"],
size = [aCoder decodeDoubleForKey:@"NSSize"],
isBold = false,
isItalic = false,
info = fontinfo(name, size);
if (fontName === "LucidaGrande" && size === 13)
if (info)
{
CPLog.debug("Removing default IB font: <"+fontName+", "+size+"> for theme default font.");
return nil;
name = info.familyName;
isBold = info.bold;
isItalic = info.italic;
}
// FIXME: Is this alwasy true?
if (fontName.indexOf("-Bold") === fontName.length - "-Bold".length)
isBold = YES;
if (fontName === "LucidaGrande" || fontName === "LucidaGrande-Bold")
fontName = "Arial";
return [self _initWithName:fontName size:size bold:isBold];
return [self _initWithName:name size:size bold:isBold italic:isItalic];
}
@end
@implementation NSFont : CPFont
+ (void)initialize
{
CPLog.debug("NSFont: default IB font: %s %f", IBDefaultFontFace, IBDefaultFontSize);
}
+ (id)cibFontForNibFont:(CPFont)aFont
{
var name = [aFont familyName];
if (name === IBDefaultFontFace)
{
var size = [aFont size];
if (size === IBDefaultFontSize)
return nil;
else
return [[CPFont alloc] _initWithName:[CPFont systemFontFace] size:size bold:[aFont isBold] italic:[aFont isItalic]];
}
return [aFont copy];
}
- (id)initWithCoder:(CPCoder)aCoder
+1 -1
View File
@@ -127,7 +127,7 @@
children.forEach(function(aChild)
{
CPLog.info("Promoted " + aChild + " to child of " + parent);
CPLog.debug("NSIBObjectData: promoted " + aChild + " to child of " + parent);
_objectsKeys.push(aChild);
_objectsValues.push(parent);
});
+90 -36
View File
@@ -1,3 +1,24 @@
/*
* NSMatrix.j
* nib2cib
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <AppKit/CPView.j>
@@ -9,61 +30,94 @@ var NSMatrixRadioModeMask = 0x40000000,
NSMatrixDrawsBackgroundMask = 0x01000000;
@implementation NSMatrix : CPObject
{
}
@implementation NSMatrix : CPView
- (id)initWithCoder:(CPCoder)aCoder
{
var view = [[CPView alloc] NS_initWithCoder:aCoder];
return [self NS_initWithCoder:aCoder];
}
var numberOfRows = [aCoder decodeIntForKey:@"NSNumRows"],
numberOfColumns = [aCoder decodeIntForKey:@"NSNumCols"],
cellSize = [aCoder decodeSizeForKey:@"NSCellSize"],
intercellSpacing = [aCoder decodeSizeForKey:@"NSIntercellSpacing"],
flags = [aCoder decodeIntForKey:@"NSMatrixFlags"],
isRadioMode = flags & NSMatrixRadioModeMask,
drawsBackground = flags & NSMatrixDrawsBackgroundMask,
backgroundColor = [aCoder decodeObjectForKey:@"NSBackgroundColor"],
cells = [aCoder decodeObjectForKey:@"NSCells"],
selectedCell = [aCoder decodeObjectForKey:@"NSSelectedCell"];
- (id)NS_initWithCoder:(CPCoder)aCoder
{
self = [super NS_initWithCoder:aCoder];
if (isRadioMode)
if (self)
{
var radioGroup = [CPRadioGroup new],
frame = CGRectMake(0.0, 0.0, cellSize.width, cellSize.height);
var numberOfRows = [aCoder decodeIntForKey:@"NSNumRows"],
numberOfColumns = [aCoder decodeIntForKey:@"NSNumCols"],
cellSize = [aCoder decodeSizeForKey:@"NSCellSize"],
intercellSpacing = [aCoder decodeSizeForKey:@"NSIntercellSpacing"],
flags = [aCoder decodeIntForKey:@"NSMatrixFlags"],
isRadioMode = flags & NSMatrixRadioModeMask,
drawsBackground = flags & NSMatrixDrawsBackgroundMask,
backgroundColor = [aCoder decodeObjectForKey:@"NSBackgroundColor"],
cells = [aCoder decodeObjectForKey:@"NSCells"],
selectedCell = [aCoder decodeObjectForKey:@"NSSelectedCell"];
for (var rowIndex = 0; rowIndex < numberOfRows; ++rowIndex)
if (isRadioMode)
{
frame.origin.x = 0;
var radioGroup = [CPRadioGroup new],
frame = CGRectMake(0.0, 0.0, cellSize.width, cellSize.height);
for (var columnIndex = 0; columnIndex < numberOfColumns; ++columnIndex)
for (var rowIndex = 0; rowIndex < numberOfRows; ++rowIndex)
{
var cell = cells[rowIndex * numberOfColumns + columnIndex],
cellView = [[CPRadio alloc] initWithFrame:frame radioGroup:radioGroup];
frame.origin.x = 0;
[cellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[cellView setTitle:[cell title]];
[cellView setBackgroundColor:[CPColor clearColor]]; // the IB default
[cellView setObjectValue:[cell objectValue]];
for (var columnIndex = 0; columnIndex < numberOfColumns; ++columnIndex)
{
var cell = cells[rowIndex * numberOfColumns + columnIndex],
cellView = [[CPRadio alloc] initWithFrame:frame radioGroup:radioGroup cell:cell];
[view addSubview:cellView];
[self addSubview:cellView];
NIB_CONNECTION_EQUIVALENCY_TABLE[[cell UID]] = cellView;
NIB_CONNECTION_EQUIVALENCY_TABLE[[cell UID]] = cellView;
frame.origin.x = CGRectGetMaxX(frame) + intercellSpacing.width;
frame.origin.x = CGRectGetMaxX(frame) + intercellSpacing.width;
}
frame.origin.y = CGRectGetMaxY(frame) + intercellSpacing.height;
}
frame.origin.y = CGRectGetMaxY(frame) + intercellSpacing.height;
if (drawsBackground)
[self setBackgroundColor:backgroundColor];
self.isa = [CPView class];
}
else
{
// Non-radio group NSMatrix is not supported
self = nil;
}
if (drawsBackground)
[view setBackgroundColor:backgroundColor];
NIB_CONNECTION_EQUIVALENCY_TABLE[[self UID]] = view;
}
return view;
return self;
}
@end
@implementation CPRadio (NS)
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup cell:(NSButtonCell)aCell
{
self = [self initWithFrame:aFrame radioGroup:aRadioGroup];
if (self)
{
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self setTitle:[aCell title]];
[self setBackgroundColor:[CPColor clearColor]]; // the IB default
[self setFont:[aCell font]];
[self setAlignment:[aCell alignment]];
[self setLineBreakMode:[aCell lineBreakMode]];
[self setImagePosition:[aCell imagePosition]];
[self setKeyEquivalent:[aCell keyEquivalent]];
[self setKeyEquivalentModifierMask:[aCell keyEquivalentModifierMask]];
[self setAllowsMixedState:[aCell allowsMixedState]];
[self setObjectValue:[aCell objectValue]];
[self setEnabled:[aCell isEnabled]];
}
return self;
}
@end
+4 -4
View File
@@ -43,17 +43,17 @@ NIB_CONNECTION_EQUIVALENCY_TABLE = {};
if (sourceUID in NIB_CONNECTION_EQUIVALENCY_TABLE)
{
CPLog.trace("Swapped object: "+_source+" for object: "+NIB_CONNECTION_EQUIVALENCY_TABLE[sourceUID]);
CPLog.debug("NSNibConnector: swapped object: " + _source + " for object: " + NIB_CONNECTION_EQUIVALENCY_TABLE[sourceUID]);
_source = NIB_CONNECTION_EQUIVALENCY_TABLE[sourceUID];
}
if (destinationUID in NIB_CONNECTION_EQUIVALENCY_TABLE)
{
CPLog.trace("Swapped object: "+_destination+" for object: "+NIB_CONNECTION_EQUIVALENCY_TABLE[destinationUID]);
CPLog.debug("NSNibConnector: swapped object: " + _destination + " for object: " + NIB_CONNECTION_EQUIVALENCY_TABLE[destinationUID]);
_destination = NIB_CONNECTION_EQUIVALENCY_TABLE[destinationUID];
}
CPLog.debug(@"Connection: " + [_source description] + " " + [_destination description] + " " + _label);
CPLog.debug(@"NSNibConnector: connection: " + [_source description] + " " + [_destination description] + " " + _label);
}
return self;
@@ -144,7 +144,7 @@ var NSTramsformers = [CPSet setWithObjects:
[_options setObject:NSValue forKey:CPKey];
}
CPLog.debug(@"Binding Connector: " + [_binding description] + " to: " + _destination + " " + [_keyPath description] + " " + [_options description]);
CPLog.debug(@"NSNibConnector: binding connector: " + [_binding description] + " to: " + _destination + " " + [_keyPath description] + " " + [_options description]);
}
return self;
+1
View File
@@ -37,6 +37,7 @@
_items = [aCoder decodeObjectForKey:@"NSTabViewItems"];
_selectedIndex = [_items indexOfObject:[aCoder decodeObjectForKey:@"NSSelectedTabViewItem"]];
_font = [aCoder decodeObjectForKey:@"NSFont"];
//_delegate = [aCoder decodeObjectForKey:@""];
+11 -8
View File
@@ -45,26 +45,29 @@
else
{
_dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
var font = [dataViewCell font],
selectedFont = nil;
if (font)
font = [NSFont cibFontForNibFont:font];
if (!font)
font = [CPFont systemFontOfSize:12.0];
font = [CPFont systemFontOfSize:[CPFont systemFontSize]];
var selectedFont = [CPFont boldFontWithName:[font familyName] size:[font size]];
[_dataView setFont:font];
[_dataView setValue:selectedFont forThemeAttribute:@"font" inState:CPThemeStateSelectedDataView];
[_dataView setLineBreakMode:CPLineBreakByTruncatingTail];
[_dataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[_dataView setValue:CGInsetMake(0.0, 5.0, 0.0, 5.0) forThemeAttribute:@"content-inset"];
var textColor = [dataViewCell textColor],
defaultColor = [_dataView currentValueForThemeAttribute:@"text-color"];
// Don't change the text color if it is not the default, that messes up the theme lookups later
if (![textColor isEqual:defaultColor])
[_dataView setTextColor:[dataViewCell textColor]];
+1 -1
View File
@@ -72,7 +72,7 @@
[self setFrameSize:CGSizeMake(frame.size.width + 7.0, frame.size.height + 7.0)];
}
CPLog.debug([self stringValue] + " => isBordered=" + [self isBordered] + ", isBezeled=" + [self isBezeled] + ", bezelStyle=" + [self bezelStyle] + "("+[cell stringValue]+", " + [cell placeholderString] + ")");
CPLog.debug("NSTextField: title=\"" + [self stringValue] + "\", placeholder=" + ([cell placeholderString] == null ? "<none>" : '"' + [cell placeholderString] + '"') + ", isBordered=" + [self isBordered] + ", isBezeled=" + [self isBezeled] + ", bezelStyle=" + [self bezelStyle]);
}
return self;
-2
View File
@@ -84,8 +84,6 @@ var NSViewAutoresizingMask = 0x3F,
@end
@implementation NSView : CPView
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
+501 -63
View File
@@ -18,11 +18,11 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
*/
@import <Foundation/Foundation.j>
@import <AppKit/CPCib.j>
@import <AppKit/AppKit.j>
@import <BlendKit/BlendKit.j>
@import "NSFoundation.j"
@import "NSAppKit.j"
@@ -30,39 +30,266 @@
@import "Nib2CibKeyedUnarchiver.j"
@import "Converter.j"
var FILE = require("file");
var OS = require("os");
var FILE = require("file"),
OS = require("os"),
SYS = require("system"),
FileList = require("jake").FileList,
stream = require("narwhal/term").stream,
var parser = new (require("narwhal/args").Parser)();
DefaultTheme = "Aristo",
BuildTypes = ["Debug", "Release"],
DefaultXibFile = "MainMenu.xib";
parser.usage("INPUT_FILE [OUTPUT_FILE]");
var parser = new (require("narwhal/args").Parser)(),
nibInfo = {};
parser.option("-F", "framework", "frameworks")
.push()
.help("Add a framework to load");
parser.option("-R", "resources")
.set()
.help("Set the Resources directory");
function main(args)
{
try
{
var options = parseOptions(args);
parser.option("--mac", "format")
.set(NibFormatMac)
.def(NibFormatUndetermined)
.help("Set format to Mac");
if (options.watch)
watch(options);
else
convert(options);
}
catch (anException)
{
CPLog.fatal([anException reason]);
OS.exit(1);
}
}
// parser.option("--iphone", "format")
// .set(NibFormatIPhone)
// .help("Set format to iPhone");
function convert(options, inputFile)
{
try
{
inputFile = inputFile || getInputFile(options.args);
parser.option("-v", "--verbose", "verbose")
.inc()
.help("Increase verbosity level");
var outputFile = getOutputFile(inputFile, options.args),
resourcesPath = "";
parser.option("-q", "--quiet", "quiet")
.set(true)
.help("No output");
if (options.resources)
{
resourcesPath = FILE.canonical(options.resources);
parser.helpful();
if (!FILE.isDirectory(resourcesPath) || !FILE.isReadable(resourcesPath))
fail("Cannot read resources at: " + resourcesPath);
}
var configPath = setSystemFontAndSize(options.configFile || "", inputFile),
themeName = "",
themeDir = options.themeDir || "";
if (themeDir)
themeName = FILE.basename(themeDir, FILE.extension(themeDir));
themeName = themeName || getDefaultThemeName();
if (!themeName)
fail("Could not determine the theme name.");
var theme = loadTheme(themeName, themeDir);
CPLog.info("\n-------------------------------------------------------------");
CPLog.info("Input : " + inputFile);
CPLog.info("Output : " + outputFile);
CPLog.info("Format : " + ["Auto", "Mac", "iPhone"][options.format]);
CPLog.info("Resources : " + resourcesPath);
CPLog.info("Frameworks : " + (options.frameworks || ""));
CPLog.info("Theme : " + themeName);
CPLog.info("Config file : " + (configPath || ""));
CPLog.info("System Font : " + [CPFont systemFontSize] + "px " + [CPFont systemFontFace]);
CPLog.info("-------------------------------------------------------------\n");
var converter = [[Converter alloc] initWithInputPath:inputFile
format:options.format
theme:theme];
[converter setOutputPath:outputFile];
[converter setResourcesPath:resourcesPath];
loadFrameworks(options.frameworks, function()
{
[converter convert];
});
return true;
}
catch (anException)
{
CPLog.fatal([anException reason]);
return false;
}
}
function watch(options)
{
var verbosity = options.quiet ? -1 : options.verbosity,
directory = options.args[0];
if (!directory)
directory = FILE.isDirectory("Resources") ? "Resources" : ".";
directory = FILE.canonical(directory);
if (!FILE.isDirectory(directory))
fail("Cannot find the directory: " + directory);
// Turn on info messages
setLogLevel(1);
CPLog.info("Watching: " + CPLogColorize(directory, "debug"));
CPLog.info("Press Control-C to stop...");
while (true)
{
var modifiedNibs = getModifiedNibs(directory);
for (var i = 0; i < modifiedNibs.length; ++i)
{
var action = modifiedNibs[i][0],
path = modifiedNibs[i][1],
label = action === "add" ? "Added:" : "Modified:",
level = action === "add" ? "info" : "debug";
CPLog.info(">> %s %s", CPLogColorize(label, level), path);
// Let the converter log however the user configured it
setLogLevel(verbosity);
var success = convert(options, path);
setLogLevel(1);
if (success)
{
if (verbosity > 0)
stream.print();
else
CPLog.warn("Conversion successful");
}
}
OS.sleep(1);
}
}
function parseOptions(args)
{
parser.usage("[--watch DIRECTORY] [INPUT_FILE [OUTPUT_FILE]]");
parser.option("--watch", "watch")
.set(true)
.help("Ask nib2cib to watch a directory for changes");
parser.option("-F", "framework", "frameworks")
.push()
.help("Add a framework to load");
parser.option("-R", "resources")
.set()
.help("Set the Resources directory");
parser.option("--mac", "format")
.set(NibFormatMac)
.def(NibFormatUndetermined)
.help("Set format to Mac");
parser.option("-t", "--theme-dir", "themeDir")
.set()
.help("A <theme>.build directory to use for theme attribute values");
parser.option("--config", "configFile")
.set()
.help("A path to an Info.plist file from which the system font and/or size can be retrieved");
// parser.option("--iphone", "format")
// .set(NibFormatIPhone)
// .help("Set format to iPhone");
parser.option("-v", "--verbose", "verbosity")
.inc()
.help("Increase verbosity level");
parser.option("-q", "--quiet", "quiet")
.set(true)
.help("No output");
parser.option("--version", "showVersion")
.action(printVersionAndExit)
.help("Show the version of nib2cib and quit");
parser.helpful();
var options = parser.parse(args, null, null, true);
if (options.args.length > 2)
{
parser.printUsage(options);
OS.exit(0);
}
setLogLevel(options.quiet ? -1 : options.verbosity);
if (!options.quiet && options.verbosity > 0)
printVersion();
return options;
}
function setLogLevel(level)
{
CPLogUnregister(CPLogPrint);
if (level === 0)
CPLogRegister(CPLogPrint, "warn", logFormatter);
else if (level === 1)
CPLogRegister(CPLogPrint, "info", logFormatter);
else if (level > 1)
CPLogRegister(CPLogPrint, null, logFormatter);
}
function getInputFile(args)
{
var inputFile = args[0] || DefaultXibFile;
if (!/^.+\.xib$/.test(inputFile))
inputFile += ".xib";
inputFile = FILE.canonical(inputFile);
if (!FILE.exists(inputFile) && FILE.basename(FILE.dirname(inputFile)) !== "Resources")
if (FILE.isDirectory("Resources"))
inputFile = FILE.resolve(inputFile, FILE.join("Resources", FILE.basename(inputFile)));
if (!FILE.isReadable(inputFile))
fail("Cannot read the input file: " + inputFile);
return inputFile;
}
function getOutputFile(inputFile, args)
{
var outputFile = null;
if (args.length > 1)
outputFile = args[1];
else
outputFile = FILE.basename(inputFile, FILE.extension(inputFile));
if (!/^.+\.cib$/.test(outputFile))
outputFile += ".cib";
outputFile = FILE.resolve(inputFile, outputFile);
if (!FILE.isWritable(FILE.dirname(outputFile)))
fail("Cannot write the output file at: " + outputFile);
return outputFile;
}
function loadFrameworks(frameworkPaths, aCallback)
{
@@ -71,7 +298,7 @@ function loadFrameworks(frameworkPaths, aCallback)
frameworkPaths.forEach(function(aFrameworkPath)
{
print("Loading " + aFrameworkPath);
CPLog.info("Loading " + aFrameworkPath);
var frameworkBundle = [[CPBundle alloc] initWithPath:aFrameworkPath];
@@ -83,44 +310,255 @@ function loadFrameworks(frameworkPaths, aCallback)
aCallback();
}
function main(args)
function logFormatter(aString, aLevel, aTitle)
{
var options = parser.parse(args, null, null, true);
if (aLevel === "info")
return aString;
else
return CPLogColorize(aString, aLevel);
}
if (options.args.length < 1 || options.args.length > 2)
function getDefaultThemeName()
{
var themeName = nil,
cappBuild = SYS.env["CAPP_BUILD"];
if (cappBuild)
{
parser.printUsage(options);
OS.exit(1);
for (var i = 0; i < BuildTypes.length; ++i)
{
var path = FILE.join(cappBuild, BuildTypes[i], "AppKit", "Info.plist");
themeName = themeNameFromPropertyList(path);
if (themeName)
break;
}
}
if (options.quiet) {}
else if (options.verbose === 0)
CPLogRegister(CPLogPrint, "warn");
else if (options.verbose === 1)
CPLogRegister(CPLogPrint, "info");
else
CPLogRegister(CPLogPrint);
CPLog.debug("Input: " + options.args[0]);
CPLog.debug("Output: " + (options.args[1] || ""));
CPLog.debug("Format: " + ["Auto","Mac","iPhone"][options.format]);
CPLog.debug("Resources: " + (options.resources || ""));
CPLog.debug("Frameworks: " + options.frameworks);
var converter = [[Converter alloc] init];
if (options.resources)
[converter setResourcesPath:options.resources];
[converter setFormat:options.format];
[converter setInputPath:options.args[0]];
if (options.args.length > 1)
[converter setOutputPath:options.args[1]];
loadFrameworks(options.frameworks, function()
{
[converter convert];
});
return themeName || DefaultTheme;
}
function themeNameFromPropertyList(path)
{
if (!FILE.isReadable(path))
return nil;
var themeName = nil,
plist = CFPropertyList.readPropertyListFromFile(path);
if (plist)
themeName = plist.valueForKey("CPDefaultTheme");
return themeName;
}
function loadTheme(themeName, themeDir)
{
if (!themeDir)
{
cappBuild = SYS.env["CAPP_BUILD"];
if (!cappBuild)
fail("$CAPP_BUILD is not set, exiting.");
if (!FILE.isDirectory(cappBuild))
fail("$CAPP_BUILD does not exist: " + cappBuild)
var baseThemeName = themeName,
pos = themeName.indexOf("-");
if (pos > 0)
baseThemeName = themeName.substr(0, pos);
themeDir = FILE.join(cappBuild, baseThemeName + ".build");
}
themeDir = FILE.canonical(themeDir);
if (!FILE.isDirectory(themeDir))
fail("Cannot find the theme directory: " + themeDir);
var themePath = null;
for (var i = 0; i < BuildTypes.length; ++i)
{
var path = FILE.join(themeDir, BuildTypes[i], "Browser.environment/Resources", themeName + ".keyedtheme");
if (FILE.isReadable(path))
{
themePath = path;
break;
}
}
if (!themePath)
fail("Could not find the keyed theme data for \"" + themeName + "\" in the directory: " + themeDir);
themePath = FILE.canonical(themePath);
var plist = FILE.read(themePath);
if (!plist)
fail("Could not read the keyed theme at: " + themePath);
// The .keyedtheme file has a header that is data I don't need. Strip it off.
var m = plist.match(/^t;\d+;/);
if (!m || m.length === 0)
fail("Invalid keyed theme data at: " + themePath);
plist = plist.substr(m[0].length);
plist = CFPropertyList.propertyListFromString(plist);
var data = [CPData dataWithPlistObject:plist],
theme = [CPKeyedUnarchiver unarchiveObjectWithData:data];
if (!theme)
fail("Could not unarchive the theme at: " + themePath);
CPLog.debug("Loaded theme: " + themePath);
return theme;
}
function setSystemFontAndSize(configFile, inputFile)
{
var configPath = null;
// First see if the user passed a config file path
if (configFile)
{
var path = FILE.canonical(configFile);
if (!FILE.isReadable(path))
fail("Cannot find the config file: " + path);
configPath = path;
}
else
{
// See if we can find an Info.plist in the parent directory of the input file,
// if the input file's directory is "Resources".
var path = FILE.canonical(FILE.dirname(inputFile));
if (FILE.basename(path) === "Resources")
{
path = FILE.join(FILE.dirname(path), "Info.plist");
if (FILE.isReadable(path))
configPath = path;
}
}
if (configPath)
{
var plist = FILE.read(configPath);
if (!plist)
fail("Could not read the Info.plist at: " + configPath);
plist = CFPropertyList.propertyListFromString(plist);
if (!plist)
fail("Could not parse the Info.plist at: " + configPath);
var systemFontFace = plist.valueForKey("CPSystemFontFace");
if (systemFontFace)
[CPFont setSystemFontFace:systemFontFace];
var systemFontSize = plist.valueForKey("CPSystemFontSize");
if (systemFontSize)
[CPFont setSystemFontSize:parseFloat(systemFontSize, 10)];
}
return configPath;
}
function getModifiedNibs(path)
{
var nibs = new FileList(FILE.join(path, "*.xib")).items(),
count = nibs.length,
newNibInfo = {},
modifiedNibs = [];
while (count--)
{
var nib = nibs[count];
newNibInfo[nib] = FILE.mtime(nib);
if (!nibInfo.hasOwnProperty(nib))
modifiedNibs.push(["add", nib]);
else
{
if (newNibInfo[nib] - nibInfo[nib] !== 0)
modifiedNibs.push(["mod", nib]);
// Remove matching nibs so that we leave
// deleted nibs in nibInfo.
delete nibInfo[nib];
}
}
for (var nib in nibInfo)
{
if (nibInfo.hasOwnProperty(nib))
CPLog.info(">> %s %s", CPLogColorize("Deleted:", "warn"), nib);
}
nibInfo = newNibInfo;
return modifiedNibs;
}
function printVersionAndExit()
{
printVersion();
OS.exit(0);
}
function printVersion()
{
/*
There are two usual possibilities for the location of the nib2cib binary.
If we are executing the installed narwhal binary, the location is:
<narwhal>/packages/cappuccino/bin/nib2cib
If we are executing the built binary, the location is:
<CAPP_BUILD>/Debug|Release/CommonJS/cappuccino/bin/nib2cib
Base on these paths we can locate nib2cib's Info.plist.
*/
var path = FILE.dirname(FILE.dirname(FILE.canonical(SYS.args[0]))),
version = null;
if (FILE.basename(path) === "narwhal")
path = FILE.join(path, "packages", "cappuccino");
path = FILE.join(path, "lib", "nib2cib", "Info.plist");
if (FILE.isReadable(path))
{
var plist = FILE.read(path);
if (!plist)
return;
plist = CFPropertyList.propertyListFromString(plist);
if (!plist)
return;
version = plist.valueForKey("CPBundleVersion");
if (version)
stream.print("nib2cib v" + version);
}
if (!version)
stream.print("<No version info available>");
}
function fail(message)
{
[CPException raise:ConverterConversionException reason:message];
}