Merge remote-tracking branch 'cappuccino/master'

This commit is contained in:
daboe01
2016-09-27 19:34:06 +02:00
49 changed files with 9807 additions and 28 deletions
+1
View File
@@ -101,6 +101,7 @@
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPTextView.j"
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
+14 -2
View File
@@ -100,8 +100,10 @@ var cachedBlackColor,
+ (CPDictionary)themeAttributes
{
return @{
@"alternate-selected-control-color": [CPNull null],
@"secondary-selected-control-color" : [CPNull null]
@"alternate-selected-control-color": [CPNull null],
@"secondary-selected-control-color": [CPNull null],
@"selected-text-background-color": [CPNull null],
@"selected-text-inactive-background-color": [CPNull null]
};
}
@@ -498,6 +500,16 @@ var cachedBlackColor,
return [[CPColor alloc] _initWithCSSString: aString];
}
+ (CPColor)selectedTextBackgroundColor
{
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-background-color"] || [CPColor colorWithHexString:"99CCFF"];
}
+ (CPColor)_selectedTextBackgroundColorUnfocussed
{
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-inactive-background-color"] || [CPColor colorWithHexString:"CCCCCC"];
}
/* @ignore */
- (id)_initWithCSSString:(CPString)aString
{
+1 -1
View File
@@ -25,7 +25,7 @@
@import "CPFont.j"
@import "CPShadow.j"
@import "CPView.j"
@import "CPText.j"
@import "CPKeyValueBinding.j"
@import "CPTrackingArea.j"
+3 -1
View File
@@ -28,7 +28,6 @@
@import "CPCompatibility.j"
@import "CGGeometry.j"
@import "CPText.j"
@import "CPTrackingArea.j"
@class CPTextField
@@ -36,6 +35,9 @@
@class CPGraphicsContext
@global CPApp
@global CPNewlineCharacter
@global CPCarriageReturnCharacter
@global CPEnterCharacter
@typedef DOMEvent
@typedef CPEventType
+38
View File
@@ -24,6 +24,7 @@
@import <Foundation/CPBundle.j>
@import "CPView.j"
@import "CPFontDescriptor.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
@@ -433,6 +434,43 @@ following:
@end
@implementation CPFont(DescriptorAdditions)
- (id)_initWithFontDescriptor:(CPFontDescriptor)fontDescriptor
{
var aName = [fontDescriptor objectForKey: CPFontNameAttribute] ,
aSize = [fontDescriptor pointSize],
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
return [self _initWithName:aName size:aSize bold:isBold italic:isItalic system:NO];
}
+ (CPFont)fontWithDescriptor:(CPFontDescriptor)fontDescriptor size:(float)aSize
{
var aName = [fontDescriptor objectForKey: CPFontNameAttribute],
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
return [self _fontWithName:aName size:aSize || [fontDescriptor pointSize] bold:isBold italic:isItalic];
}
- (CPFontDescriptor)fontDescriptor
{
var traits = 0;
if ([self isBold])
traits |= CPFontBoldTrait;
if ([self isItalic])
traits |= CPFontItalicTrait;
return [[CPFontDescriptor fontDescriptorWithName:_name size:_size] fontDescriptorWithSymbolicTraits:traits];
}
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
+208 -1
View File
@@ -22,9 +22,12 @@
@import <Foundation/CPObject.j>
@import "CPControl.j"
@import "CPFont.j"
@import "CPFontDescriptor.j"
@global CPApp
@class CPFontPanel
CPItalicFontMask = 1 << 0;
CPBoldFontMask = 1 << 1;
@@ -41,7 +44,20 @@ CPUnitalicFontMask = 1 << 24;
var CPSharedFontManager = nil,
CPFontManagerFactory = Nil;
CPFontManagerFactory = nil,
CPFontPanelFactory = nil;
/*
modifyFont: sender's tag
*/
CPNoFontChangeAction = 0;
CPViaPanelFontAction = 1;
CPAddTraitFontAction = 2;
CPSizeUpFontAction = 3;
CPSizeDownFontAction = 4;
CPHeavierFontAction = 5;
CPLighterFontAction = 6;
CPRemoveTraitFontAction = 7;
/*!
@ingroup appkit
@@ -59,6 +75,8 @@ var CPSharedFontManager = nil,
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
CPDictionary _activeChange;
unsigned _fontAction;
}
// Getting the Shared Font Manager
@@ -83,6 +101,15 @@ var CPSharedFontManager = nil,
{
CPFontManagerFactory = aClass;
}
/*!
Sets the class that will be used to create the application's
Font panel.
*/
+ (void)setFontPanelFactory:(Class)aClass
{
CPFontPanelFactory = aClass;
}
- (id)init
{
@@ -210,6 +237,7 @@ var CPSharedFontManager = nil,
{
var tag = [sender tag];
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
_fontAction = CPAddTraitFontAction;
[self sendAction];
}
@@ -219,6 +247,185 @@ var CPSharedFontManager = nil,
return [CPApp sendAction:_action to:_target from:self];
}
/*!
This method open the font panel, create it if necessary.
@param sender The object that sent the message.
*/
- (CPFontPanel)fontPanel:(BOOL)createIt
{
var panel = nil,
panelExists = [CPFontPanelFactory sharedFontPanelExists];
if ((panelExists) || (!panelExists && createIt))
panel = [CPFontPanelFactory sharedFontPanel];
return panel;
}
/*!
Convert a font to have the specified Font traits. The font is unchanged expect for the specified Font traits.
Using CPUnboldFontMask or CPUnitalicFontMask will respectively remove Bold and Italic traits.
@param aFont The font to convert.
@param fontTrait The new font traits mask.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)fontTrait
{
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
if (fontTrait & CPBoldFontMask)
symbolicTrait |= CPFontBoldTrait;
if (fontTrait & CPItalicFontMask)
symbolicTrait |= CPFontItalicTrait;
if (fontTrait & CPUnboldFontMask) /* FIXME: this only change CPFontSymbolicTrait what about CPFontWeightTrait */
symbolicTrait &= ~CPFontBoldTrait;
if (fontTrait & CPUnitalicFontMask)
symbolicTrait &= ~CPFontItalicTrait;
if (fontTrait & CPExpandedFontMask)
symbolicTrait |= CPFontExpandedTrait;
if (fontTrait & CPSmallCapsFontMask)
symbolicTrait |= CPFontSmallCapsTrait;
if (![attributes containsKey:CPFontTraitsAttribute])
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait]
forKey:CPFontTraitsAttribute];
else
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait];
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
}
/*!
Convert a font to not have the specified Font traits. The font is unchanged expect for the specified Font traits.
@param aFont The font to convert.
@param fontTrait The font traits mask to remove.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toNotHaveTrait:(CPFontTraitMask)fontTrait
{
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
if ((fontTrait & CPBoldFontMask) || (fontTrait & CPUnboldFontMask)) /* FIXME: see convertFont:toHaveTrait: about CPFontWeightTrait */
symbolicTrait &= ~CPFontBoldTrait;
if ((fontTrait & CPItalicFontMask) || (fontTrait & CPUnitalicFontMask))
symbolicTrait &= ~CPFontItalicTrait;
if (fontTrait & CPExpandedFontMask)
symbolicTrait &= ~CPFontExpandedTrait;
if (fontTrait & CPSmallCapsFontMask)
symbolicTrait &= ~CPFontSmallCapsTrait;
if (![attributes containsKey:CPFontTraitsAttribute])
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait]
forKey:CPFontTraitsAttribute];
else
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait];
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
}
/*!
Convert a font to have specified size. The font is unchanged expect for the specified size.
@param aFont The font to convert.
@param aSize The new font size.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toSize:(float)aSize
{
var descriptor = [aFont fontDescriptor];
return [[aFont class] fontWithDescriptor: descriptor size:aSize]
}
- (void)orderFrontFontPanel:(id)sender
{
[[self fontPanel:YES] orderFront:sender];
}
- (void)modifyFont:(id)sender
{
_fontAction = [sender tag];
[self sendAction];
if (_selectedFont)
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
}
/*!
This method causes the receiver to send its action message.
@param sender The object that sent the message. (a Font panel)
*/
- (void)modifyFontViaPanel:(id)sender
{
_fontAction = CPViaPanelFontAction;
if (_selectedFont)
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
[self sendAction];
}
/*!
Convert a font according to current font changes, provided by the object that initiated the font change.
@param aFont The font to convert.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont
{
var newFont = nil;
switch (_fontAction)
{
case CPNoFontChangeAction:
newFont = aFont;
break;
case CPViaPanelFontAction:
newFont = [[self fontPanel:NO] panelConvertFont:aFont];
break;
case CPAddTraitFontAction:
newFont = aFont;
if (!_activeChange)
break;
var addTraits = [_activeChange valueForKey:@"addTraits"];
if (addTraits)
newFont = [self convertFont:aFont toHaveTrait:addTraits];
break;
case CPSizeUpFontAction:
newFont = [self convertFont:aFont toSize:[aFont size] + 1.0]; /* any limit ? */
break;
case CPSizeDownFontAction:
if ([aFont size] > 1)
newFont = [self convertFont:aFont toSize:[aFont size] - 1.0];
/* else CPBeep() :-p */
break;
default:
CPLog.trace(@"-[" + [self className] + " " + _cmd + "] unsupported font action: " + _fontAction + " aFont unchanged");
newFont = aFont;
break;
}
return newFont;
}
@end
var _CPFontDetectSpan,
+1
View File
@@ -44,6 +44,7 @@ CPStringPboardType = @"CPStringPboardType";
CPURLPboardType = @"CPURLPboardType";
CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
CPRTFPboardType = @"CPRTFPboardType";
UTF8PboardType = @"public.utf8-plain-text";
+63 -6
View File
@@ -24,9 +24,15 @@
@import "CGGeometry.j"
@import "CPPlatformString.j"
@import "CPFont.j"
@import "CPCompatibility.j"
var CPStringSizeWithFontInWidthCache = {};
var CPStringSizeWithFontInWidthCache = [],
CPStringSizeWithFontHeightCache = [],
CPStringSizeMeasuringContext,
CPStringSizeIsCanvasSizingInvalid,
CPStringSizeDidTestCanvasSizingValid;
CPStringSizeCachingEnabled = YES;
@@ -53,20 +59,71 @@ CPStringSizeCachingEnabled = YES;
return [self sizeWithFont:aFont inWidth:NULL];
}
- (void) _initializeStringSizing
{
#if PLATFORM(DOM)
CPStringSizeIsCanvasSizingInvalid = YES;
if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
{
var aFont = [CPFont systemFontOfSize:12.0];
if (!CPStringSizeMeasuringContext)
CPStringSizeMeasuringContext = CGBitmapGraphicsContextCreate();
CPStringSizeMeasuringContext.font = [aFont cssString];
var teststring = "0123456879abcdefghiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.-()";
CPStringSizeIsCanvasSizingInvalid = ABS([CPPlatformString sizeOfString:teststring withFont:aFont forWidth:0].width - CPStringSizeMeasuringContext.measureText(teststring).width) > 2;
}
#endif
}
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
var size;
#if PLATFORM(DOM)
if (!CPStringSizeCachingEnabled)
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
var cacheKey = self + [aFont cssString] + aWidth,
size = CPStringSizeWithFontInWidthCache[cacheKey];
var sizeCacheForFont = CPStringSizeWithFontInWidthCache[self];
if (size === undefined)
if (sizeCacheForFont === undefined)
sizeCacheForFont = CPStringSizeWithFontInWidthCache[self] = [];
var cssString = [aFont cssString],
cacheKey = cssString + '_' + aWidth;
size = sizeCacheForFont[cacheKey];
if (size !== undefined && sizeCacheForFont.hasOwnProperty(cacheKey))
return CGSizeMakeCopy(size);
if (CPStringSizeDidTestCanvasSizingValid === undefined)
{
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
CPStringSizeWithFontInWidthCache[cacheKey] = size;
[self _initializeStringSizing];
CPStringSizeDidTestCanvasSizingValid = YES;
}
if (CPStringSizeIsCanvasSizingInvalid || aWidth > 0)
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
else
{
if (CPStringSizeMeasuringContext.font !== cssString)
CPStringSizeMeasuringContext.font = cssString;
var fontHeight = CPStringSizeWithFontHeightCache[cssString];
if (fontHeight === undefined)
fontHeight = CPStringSizeWithFontHeightCache[cssString] = [aFont defaultLineHeightForFont];
size = CGSizeMake(CPStringSizeMeasuringContext.measureText(self).width, fontHeight);
}
sizeCacheForFont[cacheKey] = size;
#else
size = CGSizeMake(0, 0);
#endif
return CGSizeMakeCopy(size);
}
+300 -5
View File
@@ -5,6 +5,13 @@
* Created by Alexander Ljungberg.
* Copyright 2010, WireLoad, LLC.
*
* additions from
*
* Daniel Boehringer on 8/02/2014.
* Copyright Daniel Boehringer on 8/02/2014.
*
*
*
* 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
@@ -20,6 +27,27 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/Foundation.j>
@import "CPPasteboard.j"
@import "CPView.j"
@global CPStringPboardType
@class CPAttributedString
@class _CPRTFParser
@protocol CPTextDelegate <CPObject>
- (BOOL)textShouldBeginEditing:(CPText)aTextObject;
- (BOOL)textShouldEndEditing:(CPText)aTextObject;
- (void)textDidBeginEditing:(CPNotification)aNotification;
- (void)textDidChange:(CPNotification)aNotification;
- (void)textDidEndEditing:(CPNotification)aNotification;
@end
CPParagraphSeparatorCharacter = 0x2029;
CPLineSeparatorCharacter = 0x2028;
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
@@ -29,6 +57,7 @@ CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
@typedef CPTextMovement
CPIllegalTextMovement = 0;
CPOtherTextMovement = 0;
CPReturnTextMovement = 16;
@@ -46,8 +75,274 @@ CPWritingDirectionLeftToRight = 0;
CPWritingDirectionRightToLeft = 1;
@typedef CPTextAlignment
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
/*
CPText notifications
*/
CPTextDidBeginEditingNotification = @"CPTextDidBeginEditingNotification";
CPTextDidChangeNotification = @"CPTextDidChangeNotification";
CPTextDidEndEditingNotification = @"CPTextDidEndEditingNotification";
/*
CPTextView Notifications
*/
CPTextViewDidChangeSelectionNotification = @"CPTextViewDidChangeSelectionNotification";
CPTextViewDidChangeTypingAttributesNotification = @"CPTextViewDidChangeTypingAttributesNotification";
/*
FIXME: move these to CPAttributed string
Make use of attributed keys in AppKit
*/
CPFontAttributeName = @"CPFontAttributeName";
CPForegroundColorAttributeName = @"CPForegroundColorAttributeName";
CPBackgroundColorAttributeName = @"CPBackgroundColorAttributeName";
CPShadowAttributeName = @"CPShadowAttributeName";
CPUnderlineStyleAttributeName = @"CPUnderlineStyleAttributeName";
CPSuperscriptAttributeName = @"CPSuperscriptAttributeName";
CPBaselineOffsetAttributeName = @"CPBaselineOffsetAttributeName";
CPAttachmentAttributeName = @"CPAttachmentAttributeName";
CPLigatureAttributeName = @"CPLigatureAttributeName";
CPKernAttributeName = @"CPKernAttributeName";
@implementation CPText : CPView
{
BOOL _isEditable @accessors(getter=isEditable, setter=setEditable:);
BOOL _isSelectable @accessors(getter=isSelectable, setter=setSelectable:);
BOOL _isRichText @accessors(getter=isRichText, setter=setRichText:);
}
- (void)setSelectable:(BOOL)flag
{
[self willChangeValueForKey:@"selectable"];
_isSelectable = flag;
[self didChangeValueForKey:@"selectable"];
if (!flag)
[self setEditable:flag];
}
- (void)setEditable:(BOOL)flag
{
[self willChangeValueForKey:@"editable"];
_isEditable = flag;
[self didChangeValueForKey:@"editable"];
if (flag)
[self setSelectable:flag];
}
- (void)changeFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)copy:(id)sender
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard];
// put plain representation on the pasteboad unconditionally
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:[[self stringValue] substringWithRange:selectedRange] forType:CPStringPboardType];
}
- (id)_stringForPasting
{
var pasteboard = [CPPasteboard generalPasteboard],
dataForPasting = [pasteboard stringForType:CPRTFPboardType],
stringForPasting = [pasteboard stringForType:CPStringPboardType];
if (dataForPasting || [stringForPasting hasPrefix:"{\\rtf1\\ansi"])
stringForPasting = [[_CPRTFParser new] parseRTF:dataForPasting ? dataForPasting : stringForPasting];
if (![self isRichText] && [stringForPasting isKindOfClass:[CPAttributedString class]])
stringForPasting = stringForPasting._string;
return stringForPasting;
}
- (void)paste:(id)sender
{
var stringForPasting = [self _stringForPasting];
if (stringForPasting)
[self insertText:stringForPasting];
}
- (void)copyFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)delete:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPFont)font:(CPFont)aFont
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return nil;
}
- (BOOL)isHorizontallyResizable
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (BOOL)isRulerVisible
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (BOOL)isVerticallyResizable
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (CGSize)maxSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CGSizeMake(0,0);
}
- (CGSize)minSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CGSizeMake(0,0);
}
- (void)pasteFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)scrollRangeToVisible:(CPRange)aRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)selectedAll:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPRange)selectedRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CPMakeRange(CPNotFound, 0);
}
- (void)setFont:(CPFont)aFont
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setFont:(CPFont)aFont range:(CPRange)aRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setHorizontallyResizable:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setMaxSize:(CGSize)aSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setMinSize:(CGSize)aSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setString:(CPString)aString
{
[self replaceCharactersInRange:CPMakeRange(0, [[self string] length]) withString:aString];
}
- (void)setUsesFontPanel:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setVerticallyResizable:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPString)string
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return nil;
}
- (void)underline:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (BOOL)usesFontPanel
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
@end
var CPTextViewIsEditableKey = @"CPTextViewIsEditableKey",
CPTextViewIsSelectableKey = @"CPTextViewIsSelectableKey",
CPTextViewIsRichTextKey = @"CPTextViewIsRichTextKey";
@implementation CPText (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self setSelectable:[aCoder decodeBoolForKey:CPTextViewIsSelectableKey]];
[self setEditable:[aCoder decodeBoolForKey:CPTextViewIsEditableKey]];
[self setRichText:[aCoder decodeBoolForKey:CPTextViewIsRichTextKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextViewIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextViewIsSelectableKey];
[aCoder encodeBool:_isRichText forKey:CPTextViewIsRichTextKey];
}
@end
+315
View File
@@ -0,0 +1,315 @@
/*
* CPFontDescriptor.j
* AppKit
*
* Created by Emmanuel Maillard on 07/03/10.
* Copyright Emmanuel Maillard 2010.
*
* 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>
/*
Font descriptor dictionary keys
*/
/*
CPFontNameAttribute contains a CPString that specified the font name
(may be an name list like: 'Marker Felt, Lucida Grande, Helvetica')
*/
CPFontNameAttribute = @"CPFontNameAttribute";
/*
CPFontSizeAttribute contains a CPString that specified the font size
(as a float value)
*/
CPFontSizeAttribute = @"CPFontSizeAttribute";
/*
CPFontTraitsAttribute a CPDictionary that contains font traits keys
(CPFontSymbolicTrait or CPFontWeightTrait)
*/
CPFontTraitsAttribute = @"CPFontTraitsAttribute";
// Font traits dictionary keys
/*
CPFontSymbolicTrait a CPNumber that contains CPFontFamilyClass and
typeface information flags.
*/
CPFontSymbolicTrait = @"CPFontSymbolicTrait";
/*
CPFontWeightTrait
We use CPString with CSS string values for font weight
(normal | bold | bolder | lighter | 100 | 200 | 300 | 400
| 500 | 600 | 700 | 800 | 900)
NOTE: Cocoa compatibility issue: NSFontWeightTrait are NSNumber for
font weight (from -1.0 to 1.0, 0.0 for normal weight).
*/
CPFontWeightTrait = @"CPFontWeightTrait";
/*
CPFontFamilyClass
*/
CPFontUnknownClass = 0 << 28;
CPFontOldStyleSerifsClass = 1 << 28;
CPFontTransitionalSerifsClass = 2 << 28;
CPFontModernSerifsClass = 3 << 28;
CPFontClarendonSerifsClass = 4 << 28;
CPFontSlabSerifsClass = 5 << 28;
CPFontFreeformSerifsClass = 7 << 28;
CPFontSansSerifClass = 8 << 28;
CPFontSerifClass = (CPFontOldStyleSerifsClass | CPFontTransitionalSerifsClass |
CPFontModernSerifsClass | CPFontClarendonSerifsClass |
CPFontSlabSerifsClass | CPFontFreeformSerifsClass);
CPFontFamilyClassMask = 0xF0000000;
/*
Typeface information
*/
CPFontItalicTrait = 1 << 0;
CPFontBoldTrait = 1 << 1;
CPFontExpandedTrait = 1 << 5; /* TODO: CCS 3 font-stretch */
CPFontCondensedTrait = 1 << 6;
CPFontSmallCapsTrait = 1 << 7;
/*!
@ingroup appkit
@class CPFontDescriptor
*/
@implementation CPFontDescriptor : CPObject
{
CPDictionary _attributes;
}
/*!
Returns a font descriptor with the specified attributes.
@param attributes a dictionary that describe the desired font descriptor
@return the requested font descriptor
*/
+ (CPFontDescriptor)fontDescriptorWithFontAttributes:(CPDictionary)attributes
{
return [[CPFontDescriptor alloc] initWithFontAttributes:attributes];
}
/*!
Returns a font descriptor with the specified name and size.
@param fontName the name of the font
@param aSize the size of the font (in points)
@return the requested font descriptor
*/
+ (CPFontDescriptor)fontDescriptorWithName:(CPString)fontName size:(float)size
{
return [[CPFontDescriptor alloc] initWithFontAttributes:[CPDictionary dictionaryWithObjects:[fontName, [CPString stringWithString:size + '']] forKeys:[CPFontNameAttribute,CPFontSizeAttribute]]];
}
/*!
Initialize a font descriptor with the specified attributes.
@param attributes a dictionary that describe the desired font descriptor
@return the requested font descriptor
*/
- (id)initWithFontAttributes:(CPDictionary)attributes
{
if (self = [super init])
{
_attributes = [[CPMutableDictionary alloc] init];
if (attributes)
[_attributes addEntriesFromDictionary:attributes];
}
return self;
}
/*!
Returns a new font descriptor that is the same as the receiver but with the
specified attributes taking precedence over the existing ones.
@param attributes a dictionary that describe the desired font descriptor
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorByAddingAttributes:(CPDictionary)attributes
{
var attrib = [_attributes copy];
[attrib addEntriesFromDictionary:attributes];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
/*!
Returns a new font descriptor that is the same as the receiver but with the specified size taking precedence over the existing ones.
@param aSize the new size
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorWithSize:(float)aSize
{
var attrib = [_attributes copy];
[attrib setObject:[CPString stringWithString:aSize + ''] forKey:CPFontSizeAttribute];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
/*!
Returns a new font descriptor that is the same as the receiver but with
the specified symbolic traits taking precedence over the existing ones.
@param symbolicTraits the desired new symbolic traits
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorWithSymbolicTraits:(CPFontSymbolicTraits)symbolicTraits
{
var attrib = [_attributes copy];
if ([attrib objectForKey:CPFontTraitsAttribute])
[[attrib objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
forKey:CPFontSymbolicTrait];
else
[attrib setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
forKey:CPFontSymbolicTrait] forKey:CPFontTraitsAttribute];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
- (id)objectForKey:(id)aKey
{
return [_attributes objectForKey:aKey];
}
- (CPDictionary)fontAttributes
{
return _attributes;
}
- (float)pointSize
{
var value = [_attributes objectForKey:CPFontSizeAttribute];
return value ? [value floatValue] : 0.0;
}
- (CPFontSymbolicTraits)symbolicTraits
{
var traits = [_attributes objectForKey:CPFontTraitsAttribute];
return (traits && [traits objectForKey:CPFontSymbolicTrait]) ? [[traits objectForKey:CPFontSymbolicTrait] unsignedIntValue] : 0;
}
@end
var CPFontDescriptorAttributesKey = @"CPFontDescriptorAttributesKey";
@implementation CPFontDescriptor (CPCoding)
/*!
Initializes the font descriptor from a coder.
@param aCoder the coder from which to read the font descriptor data
@return the initialized font
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self initWithFontAttributes:[aCoder decodeObjectForKey:CPFontDescriptorAttributesKey]];
}
/*!
Writes the font descriptor to a coder.
@param aCoder the coder to which the data will be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_attributes forKey:CPFontDescriptorAttributesKey];
}
@end
var _wrapNameRegEx = new RegExp(/(\w+\s+\w+)(,*)/g);
/*
Helper methods to CPFont for generating CSS font style
*/
@implementation CPFontDescriptor (CPFontCSSHelper)
- (CPString)fontStyleCSSString
{
return [self symbolicTraits] & CPFontItalicTrait ? @"italic" : @"normal";
}
- (CPString)fontWeightCSSString
{
var traitsAttributes = [_attributes objectForKey:CPFontTraitsAttribute];
if (traitsAttributes)
{
/* give preference to CPFontWeightTrait */
if ([traitsAttributes objectForKey:CPFontWeightTrait])
return [traitsAttributes objectForKey:CPFontWeightTrait];
/* else fallback to facetype symbolic traits */
if ([self symbolicTraits] & CPFontBoldTrait)
return @"bold";
}
return @"normal";
}
- (CPString)fontSizeCSSString
{
return [_attributes objectForKey:CPFontSizeAttribute] ? [[_attributes objectForKey:CPFontSizeAttribute] intValue] + "px" : @"";
}
- (CPString)fontFamilyCSSString
{
var aName = @"";
if ([_attributes objectForKey:CPFontNameAttribute])
aName += [_attributes objectForKey:CPFontNameAttribute].replace(_wrapNameRegEx, '"$1"$2');
var symbolicTraits = [self symbolicTraits];
if (symbolicTraits)
{
if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSansSerifClass)
aName += @", sans-serif";
else if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSerifClass)
aName += @", serif";
}
return aName;
}
- (CPString)fontVariantCSSString
{
if ([self symbolicTraits] & CPFontSmallCapsTrait)
return @"small-caps";
return @"normal";
}
- (CPString)cssString
{
return [CPString stringWithString:[self fontStyleCSSString] + " "
+ [self fontVariantCSSString] + " "
+ [self fontWeightCSSString] + " "
+ [self fontSizeCSSString] + " "
+ [self fontFamilyCSSString]];
}
@end
+502
View File
@@ -0,0 +1,502 @@
/*
* CPFontPanel.j
* AppKit
*
* TODOs:
* 1. make browser-width for size smaller and fix columns
* 2. sampleview is currently not shown
* 3. add all the missing features from the MacOS X counterpart
*
*
* Created by Daniel Boehringer on 2/JAN/2014.
* All modifications copyright Daniel Boehringer 2013.
* Extensive code formatting and review by Andrew Hankinson
* Based on original work by
* Created by Emmanuel Maillard on 06/03/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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 "CPPanel.j"
@import "CPColorWell.j"
@import "CPColorPanel.j"
@import "CPBrowser.j"
@import "CPText.j"
@import "CPFontManager.j"
@class CPTextStorage
@class CPLayoutManager
@class CPTextContainer
@class CPFontManager
/*
Collection indexes
*/
var kTypefaceIndex_Normal = 0,
kTypefaceIndex_Italic = 1,
kTypefaceIndex_Bold = 2,
kTypefaceIndex_BoldItalic = 3,
kToolbarHeight = 32,
kBorderSpacing = 6,
kInnerSpacing = 2,
kNothingChanged = 0,
kFontNameChanged = 1,
kTypefaceChanged = 2,
kSizeChanged = 3,
kTextColorChanged = 4,
kBackgroundColorChanged = 5,
kUnderlineChanged = 6,
kWeightChanged = 7,
_sharedFontPanel;
// FIXME<!> Locale support
var _availableTraits= [@"Normal", @"Italic", @"Bold", @"Bold Italic"],
_availableSizes = [@"9", @"10", @"11", @"12", @"13", @"14", @"18", @"24", @"36", @"48", @"72", @"96"];
@implementation _CPFontPanelSampleView : CPView
{
CPLayoutManager _layoutManager;
CPTextStorage _textStorage;
CPTextContainer _textContainer;
}
- (id)initWithFrame:(CGRect)rect
{
if (self = [super initWithFrame:rect])
{
_textStorage = [[CPTextStorage alloc] init];
_layoutManager = [[CPLayoutManager alloc] init];
_textContainer = [[CPTextContainer alloc] init];
[_layoutManager addTextContainer:_textContainer];
[_textStorage addLayoutManager:_layoutManager];
}
return self;
}
- (void)setAttributedString:(CPAttributedString)aSting
{
[_textStorage replaceCharactersInRange:CPMakeRange(0, [_textStorage length])
withAttributedString:aSting];
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)rect
{
var ctx = [[CPGraphicsContext currentContext] graphicsPort],
glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer],
usedRect = [_layoutManager usedRectForTextContainer:_textContainer],
bounds = [self bounds],
pos = CGPointMake((bounds.size.width - usedRect.size.width) / 2.0, (bounds.size.height - usedRect.size.height) / 2.0);
CGContextSaveGState(ctx);
CGContextSetFillColor(ctx, [CPColor whiteColor]);
CGContextFillRect(ctx, bounds);
CGContextRestoreGState(ctx);
[_layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:pos];
}
@end
/*!
@ingroup appkit
@class CPFontPanel
*/
@implementation CPFontPanel : CPPanel
{
id _fontBrowser;
id _traitBrowser;
id _sizeBrowser;
CPArray _availableFonts;
id _textColorWell;
CPColor _textColor;
int _currentColorButtonTag;
BOOL _setupDone;
int _fontChanges;
_CPFontPanelSampleView _sampleView;
}
#pragma mark -
#pragma mark Class methods
/*!
Check if the shared Font panel exists.
*/
+ (BOOL)sharedFontPanelExists
{
return _sharedFontPanel !== nil;
}
/*!
Return the shared Font panel.
*/
+ (CPFontPanel)sharedFontPanel
{
if (!_sharedFontPanel)
_sharedFontPanel = [[CPFontPanel alloc] init];
return _sharedFontPanel;
}
#pragma mark -
#pragma mark Init methods
/*! @ignore */
- (id)init
{
if (self = [super initWithContentRect:CGRectMake(100, 90, 450, 394) styleMask:(CPTitledWindowMask | CPClosableWindowMask /*| CPResizableWindowMask*/ )])
{
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
[self setTitle:@"Font Panel"];
[self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(378, 394)];
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
_textColor = [CPColor blackColor];
_setupDone = NO;
_fontChanges = kNothingChanged;
}
return self;
}
/*! @ignore */
- (void)_setupToolbarView
{
var colorPanel = [CPColorPanel sharedColorPanel];
_toolbarView = [[CPView alloc] initWithFrame:CGRectMake(0, kBorderSpacing, CGRectGetWidth([self frame]), kToolbarHeight)];
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
// Text color
_textColorWell = [[CPColorWell alloc] initWithFrame:CGRectMake(10, 0, 25, 25)];
[_textColorWell setColor:_textColor];
[_toolbarView addSubview:_textColorWell];
[colorPanel setTarget:self];
[colorPanel setAction:@selector(changeColor:)];
}
- (void)_setupBrowser:(CPBrowser)aBrowser
{
[aBrowser setTarget:self];
[aBrowser setAction:@selector(browserClicked:)];
[aBrowser setDoubleAction:@selector(dblClicked:)];
[aBrowser setAllowsEmptySelection:NO];
[aBrowser setAllowsMultipleSelection:NO];
[aBrowser setDelegate:self];
[[self contentView] addSubview:aBrowser];
}
- (void)_setupContents
{
if (_setupDone)
return;
_setupDone = YES;
[self _setupToolbarView];
var contentView = [self contentView],
label = [CPTextField labelWithTitle:@"Font name"],
contentBounds = [contentView bounds],
upperView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(contentBounds), CGRectGetHeight(contentBounds) - (kBorderSpacing + kToolbarHeight + kInnerSpacing))];
[contentView addSubview:_toolbarView];
_fontBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(10, 35, 150, 350)];
_traitBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(155, 35, 150, 350)];
_sizeBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(300, 35, 140, 350)];
[self _setupBrowser:_fontBrowser];
[self _setupBrowser:_traitBrowser];
[self _setupBrowser:_sizeBrowser];
[[CPNotificationCenter defaultCenter] addObserver:self
selector:@selector(textViewDidChangeSelection:)
name:CPTextViewDidChangeSelectionNotification
object:nil];
}
- (void)textViewDidChangeSelection:(CPNotification)notification
{
[self _refreshWithTextView:[notification object]];
}
- (void)_refreshWithTextView:(CPTextView)textView
{
if (![self isVisible])
return;
var attribs = [textView _attributesForFontPanel],
font = [attribs objectForKey:CPFontAttributeName] || [[textView textStorage] font] || [CPFont systemFontOfSize:12.0],
color = [attribs objectForKey:CPForegroundColorAttributeName];
if (!font)
return;
var trait = kTypefaceIndex_Normal;
if ([font isItalic] && [font isBold])
trait = kTypefaceIndex_BoldItalic;
else if ([font isItalic])
trait = kTypefaceIndex_Italic;
else if ([font isBold])
trait = kTypefaceIndex_Bold;
[self setCurrentFont:font];
[self setCurrentTrait:trait];
[self setCurrentSize:[font size] + ""]; //cast to string
if (!color)
return;
[_textColorWell setColor:color];
}
- (void)orderFront:(id)sender
{
[self _setupContents];
[super orderFront:sender];
[self _refreshWithTextView:[[CPApp keyWindow] firstResponder]];
}
- (void)reloadDefaultFontFamilies
{
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
}
- (BOOL)worksWhenModal
{
return YES;
}
/*!
@param aFont the font to convert.
@return The converted font or \c aFont if failed to convert.
*/
- (CPFont)panelConvertFont:(CPFont)aFont
{
var newFont = aFont,
index = 0;
switch (_fontChanges)
{
case kFontNameChanged:
newFont = [CPFont fontWithDescriptor:[[aFont fontDescriptor] fontDescriptorByAddingAttributes:
[CPDictionary dictionaryWithObject:[self currentFont] forKey:CPFontNameAttribute]] size:0.0];
break;
case kTypefaceChanged:
index = [self currentTrait];
if (index == kTypefaceIndex_BoldItalic)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask | CPItalicFontMask];
else if (index == kTypefaceIndex_Bold)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask];
else if (index == kTypefaceIndex_Italic)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPItalicFontMask];
else
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toNotHaveTrait:CPBoldFontMask | CPItalicFontMask];
break;
case kSizeChanged:
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toSize:[self currentSize]];
break;
case kNothingChanged:
break;
default:
CPLog.trace(@"FIXME: -[" + [self className] + " " + _cmd + "] unhandled _fontChanges: " + _fontChanges);
break;
}
return newFont;
}
- (void)setCurrentSize:(CGSize)aSize
{
[_sizeBrowser selectRow:[_availableSizes indexOfObject:aSize] inColumn:0];
}
- (CPString)currentSize
{
return [_sizeBrowser selectedItem];
}
- (void)setCurrentFont:(CPFont)aFont
{
[_fontBrowser selectRow:[_availableFonts indexOfObject:[aFont familyName]] inColumn:0];
}
- (CPString)currentFont
{
return [_fontBrowser selectedItem];
}
- (void)setCurrentTrait:(unsigned)aTrait
{
var row = 0;
switch (aTrait)
{
case kTypefaceIndex_Italic:
row = 1;
break;
case kTypefaceIndex_Bold:
row = 2;
break;
case kTypefaceIndex_BoldItalic:
row = 3;
break;
}
[_traitBrowser selectRow:row inColumn:0];
}
// FIXME<!> Locale support
- (unsigned)currentTrait
{
var sel = [_traitBrowser selectedItem];
if (sel === "Italic")
return kTypefaceIndex_Italic;
if (sel === "Bold")
return kTypefaceIndex_Bold;
if (sel === "Bold Italic")
return kTypefaceIndex_BoldItalic;
return kTypefaceIndex_Normal;
}
/*!
Set the selected font in Font panel.
@param font the selected font
@param flag if \c the current selection have multiple fonts.
*/
- (void)setPanelFont:(CPFont)font isMultiple:(BOOL)flag
{
[self _setupContents];
if ([self currentFont] !== [font familyName])
[self setCurrentFont:[font familyName]];
if ([self currentSize] != [font size])
[self setCurrentSize:[font size]];
var typefaceIndex = kTypefaceIndex_Normal,
symbolicTraits = [[font fontDescriptor] symbolicTraits];
if ((symbolicTraits & CPFontItalicTrait) && (symbolicTraits & CPFontBoldTrait))
typefaceIndex = kTypefaceIndex_BoldItalic;
else if (symbolicTraits & CPFontItalicTrait)
typefaceIndex = kTypefaceIndex_Italic;
else if (symbolicTraits & CPFontBoldTrait)
typefaceIndex = kTypefaceIndex_Bold;
if ([self currentTrait] != typefaceIndex)
[self setCurrentTrait:typefaceIndex ];
[_sampleView setAttributedString: [[CPAttributedString alloc] initWithString:[font familyName]
attributes:[CPDictionary dictionaryWithObjects:[font, [CPColor blackColor]]
forKeys:[CPFontAttributeName, CPForegroundColorAttributeName]]]];
_fontChanges = kNothingChanged;
}
- (void)changeColor:(id)sender
{
_textColor = [sender color];
_fontChanges = kTextColorChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
////////////////////////////////////////////////////////////////////
// TODO: ask CPFontManager for traits //
- (void)browserClicked:(id)aBrowser
{
if (aBrowser === _fontBrowser)
{
_fontChanges = kFontNameChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
else if (aBrowser === _traitBrowser)
{
_fontChanges = kTypefaceChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
else if (aBrowser === _sizeBrowser)
{
_fontChanges = kSizeChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
}
- (void)dblClicked:(id)sender
{
// alert("DOUBLE");
}
- (id)browser:(id)aBrowser numberOfChildrenOfItem:(id)anItem
{
if (aBrowser === _fontBrowser)
return [_availableFonts count];
if (aBrowser === _traitBrowser)
return [_availableTraits count]
return [_availableSizes count]
}
- (id)browser:(id)aBrowser child:(int)index ofItem:(id)anItem
{
if (aBrowser === _fontBrowser)
return [_availableFonts objectAtIndex:index];
if (aBrowser === _traitBrowser)
return [_availableTraits objectAtIndex:index];
return [_availableSizes objectAtIndex:index];
}
- (id)browser:(id)aBrowser objectValueForItem:(id)anItem
{
return anItem;
}
- (BOOL)browser:(id)aBrowser isLeafItem:(id)anItem
{
return YES;
}
@end
[CPFontManager setFontPanelFactory:[CPFontPanel class]];
File diff suppressed because it is too large Load Diff
+223
View File
@@ -0,0 +1,223 @@
/*
* CPParagraphStyle.j
* AppKit
*
* FIXME
* This is basically a stub.
* We need to store all the spacing informations as well as writing direction (among others)
*
* Created by Daniel Boehringer on 11/01/2014
* Copyright Daniel Boehringer 2014.
*
* 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 <Foundation/CPArray.j>
@import "CPText.j"
CPLeftTabStopType = 0;
CPParagraphStyleAttributeName = @"CPParagraphStyleAttributeName";
var _sharedDefaultParagraphStyle,
_defaultTabStopArray;
@implementation CPParagraphStyle : CPObject
{
CPArray _tabStops @accessors(property=tabStops);
CPTextAlignment _alignment @accessors(property=alignment);
unsigned _firstLineHeadIndent @accessors(property=firstLineHeadIndent);
unsigned _headIndent @accessors(property=headIndent);
unsigned _tailIndent @accessors(property=tailIndent);
unsigned _paragraphSpacing @accessors(property=paragraphSpacing);
unsigned _minimumLineHeight @accessors(property=minimumLineHeight);
unsigned _maximumLineHeight @accessors(property=maximumLineHeight);
unsigned _lineSpacing @accessors(property=lineSpacing);
}
#pragma mark -
#pragma mark Class methods
+ (CPParagraphStyle)defaultParagraphStyle
{
if (!_sharedDefaultParagraphStyle)
_sharedDefaultParagraphStyle = [self new];
return _sharedDefaultParagraphStyle;
}
+ (CPArray)_defaultTabStops
{
if (!_defaultTabStopArray)
{
var i;
_defaultTabStopArray = [];
// <!> FIXME: Define constants for these magic numbers: 13, 28
for (i = 1; i < 16 ; i++)
{
_defaultTabStopArray.push([[CPTextTab alloc] initWithType:CPLeftTabStopType location:i * 28]);
}
}
return _defaultTabStopArray;
}
#pragma mark -
#pragma mark Init methods
- (id)init
{
[self _initWithDefaults];
return self;
}
- (CPParagraphStyle)initWithParagraphStyle:(CPParagraphStyle)other
{
self = [super init];
_tabStops = [other._tabStops copy];
_alignment = other._alignment;
_firstLineHeadIndent = other._firstLineHeadIndent;
_headIndent = other._headIndent;
_tailIndent = other._tailIndent;
_paragraphSpacing = other._paragraphSpacing;
_minimumLineHeight = other._minimumLineHeight;
_maximumLineHeight = other._maximumLineHeight;
_lineSpacing = other._lineSpacing;
return self;
}
- (void)_initWithDefaults
{
_alignment = CPLeftTextAlignment;
_tabStops = [[[self class] _defaultTabStops] copy];
}
- (void)addTabStop:(CPTextTab)aStop
{
_tabStops.push(aStop);
}
- (id)copy
{
var other = [[self class] alloc];
return [other initWithParagraphStyle:self];
}
@end
var CPParagraphStyleTabStopsKey = @"CPParagraphStyleTabStopsKey",
CPParagraphStyleAlignmentKey = @"CPParagraphStyleAlignmentKey",
CPParagraphStyleFirstLineHeadIndentKey = @"CPParagraphStyleFirstLineHeadIndentKey",
CPParagraphStyleHeadIndentKey = @"CPParagraphStyleHeadIndentKey",
CPParagraphStyleTailIndentKey = @"CPParagraphStyleTailIndentKey",
CPParagraphStyleParagraphSpacingKey = @"CPParagraphStyleParagraphSpacingKey",
CPParagraphStyleMinimumLineHeightKey = @"CPParagraphStyleMinimumLineHeightKey",
CPParagraphStyleMaximumLineHeightKey = @"CPParagraphStyleMaximumLineHeightKey",
CPParagraphStyleLineSpacingKey = @"CPParagraphStyleLineSpacingKey";
@implementation CPParagraphStyle (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [self init];
if (self)
{
_tabStops = [aCoder decodeObjectForKey:"CPParagraphStyleTabStopsKey"];
_alignment = [aCoder decodeIntForKey:"CPParagraphStyleAlignmentKey"];
_firstLineHeadIndent = [aCoder decodeIntForKey:"CPParagraphStyleFirstLineHeadIndentKey"];
_headIndent = [aCoder decodeIntForKey:"CPParagraphStyleHeadIndentKey"];
_tailIndent = [aCoder decodeIntForKey:"CPParagraphStyleTailIndentKey"];
_paragraphSpacing = [aCoder decodeIntForKey:"CPParagraphStyleParagraphSpacingKey"];
_minimumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMinimumLineHeightKey"];
_maximumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMaximumLineHeightKey"];
_lineSpacing = [aCoder decodeIntForKey:"CPParagraphStyleLineSpacingKey"];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[aCoder encodeInt:_alignment forKey:"CPParagraphStyleAlignmentKey"];
[aCoder encodeObject:_tabStops forKey:"CPParagraphStyleTabStopsKey"];
[aCoder encodeInt:_firstLineHeadIndent forKey:"CPParagraphStyleFirstLineHeadIndentKey"];
[aCoder encodeInt:_headIndent forKey:"CPParagraphStyleHeadIndentKey"];
[aCoder encodeInt:_tailIndent forKey:"CPParagraphStyleTailIndentKey"];
[aCoder encodeInt:_paragraphSpacing forKey:"CPParagraphStyleParagraphSpacingKey"];
[aCoder encodeInt:_minimumLineHeight forKey:"CPParagraphStyleMinimumLineHeightKey"];
[aCoder encodeInt:_maximumLineHeight forKey:"CPParagraphStyleMaximumLineHeightKey"];
[aCoder encodeInt:_lineSpacing forKey:"CPParagraphStyleLineSpacingKey"];
}
@end
@implementation CPTextTab : CPObject
{
int _type @accessors(property = tabStopType);
double _location @accessors(property = location);
}
- (id)initWithType:(CPTabStopType) aType location:(double) aLocation
{
if ([self = [super init]])
{
_type = aType;
_location = aLocation;
}
return self;
}
@end
var CPTextTabTypeKey = @"CPTextTabTypeKey",
CPTextTabLocationKey = @"CPTextTabLocationKey";
@implementation CPTextTab (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [self init];
if (self)
{
_type = [aCoder decodeIntForKey:"CPTextTabTypeKey"];
_location = [aCoder decodeDoubleForKey:"CPTextTabLocationKey"];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[aCoder encodeInt:_type forKey:"CPTextTabTypeKey"];
[aCoder encodeDouble:_location forKey:"CPTextTabLocationKey"];
}
@end
+255
View File
@@ -0,0 +1,255 @@
/*
* CPTextContainer.j
* AppKit
*
* Created by Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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/CPGeometry.j>
@import "CPLayoutManager.j"
@class CPTextView
@class CPLayoutManager
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepLeft = 0;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepRight = 1;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepDown = 2;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepUp = 3;
/*
@global
@group CPLineMovementDirection
*/
CPLineDoesntMoves = 0;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesLeft = 1;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesRight = 2;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesDown = 3;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesUp = 4;
/*!
@ingroup appkit
@class CPTextContainer
*/
@implementation CPTextContainer : CPObject
{
float _lineFragmentPadding @accessors(property=lineFragmentPadding);
CGSize _size @accessors(property=containerSize)
CPLayoutManager _layoutManager @accessors(property=layoutManager);
CPTextView _textView @accessors(property=textView);
BOOL _inResizing;
}
#pragma mark -
#pragma mark Init methods
- (id)initWithContainerSize:(CGSize)aSize
{
self = [super init];
if (self)
{
_size = aSize;
[self _init];
}
return self;
}
- (id)init
{
return [self initWithContainerSize:CPMakeSize(1e7, 1e7)];
}
- (void)_init
{
_lineFragmentPadding = 0.0;
_layoutManager = [[CPLayoutManager alloc] init];
[_layoutManager addTextContainer:self];
}
#pragma mark -
#pragma mark Setter methods
- (void)setContainerSize:(CGSize)someSize
{
var oldSize = _size;
_size = CGSizeMakeCopy(someSize);
if (oldSize.width != _size.width)
{
_inResizing = YES;
[_layoutManager invalidateLayoutForCharacterRange:CPMakeRange(0, [[_layoutManager textStorage] length])
isSoft:NO
actualCharacterRange:NULL];
[_layoutManager _validateLayoutAndGlyphs];
[_textView sizeToFit]; // this is necessary to adopt the height of CPTextView in case of rewrapping
_inResizing = NO;
}
}
// Controls whether the receiver adjusts the width of its bounding rectangle when its text view is resized.
- (void)setWidthTracksTextView:(BOOL)flag
{
[_textView setPostsFrameChangedNotifications:flag];
if (flag)
{
[[CPNotificationCenter defaultCenter] addObserver:self
selector:@selector(textViewFrameChanged:)
name:CPViewFrameDidChangeNotification
object:_textView];
}
else
{
[[CPNotificationCenter defaultCenter] removeObserver:self
name:CPViewFrameDidChangeNotification
object:_textView];
}
}
- (void)textViewFrameChanged:(CPNotification)aNotification
{
var newSize = CGSizeMake([_textView frame].size.width, _size.height);
[self setContainerSize:newSize];
}
- (void)setTextView:(CPTextView)aTextView
{
if (_textView)
{
[self _removeAllLines];
[_textView setTextContainer:nil];
}
_textView = aTextView;
if (_textView)
[_textView setTextContainer:self];
[_layoutManager textContainerChangedTextView:self];
}
- (BOOL)containsPoint:(CGPoint)aPoint
{
return CGRectContainsPoint(CGRectMake(0, 0, _size.width, _size.height), aPoint);
}
- (BOOL)isSimpleRectangularTextContainer
{
return YES;
}
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect
sweepDirection:(CPLineSweepDirection)sweep
movementDirection:(CPLineMovementDirection)movement
remainingRect:(CGRectPointer)remainingRect
{
var resultRect = CGRectCreateCopy(proposedRect);
if (sweep != CPLineSweepRight || movement != CPLineMovesDown)
{
CPLog.trace(@"FIXME: unsupported sweep (" + sweep + ") or movement (" + movement + ")");
return CGRectMakeZero();
}
if (resultRect.origin.x + resultRect.size.width > _size.width)
resultRect.size.width = _size.width - resultRect.origin.x;
if (resultRect.size.width < 0)
resultRect = CGRectMakeZero();
if (remainingRect)
{
remainingRect.origin.x = resultRect.origin.x + resultRect.size.width;
remainingRect.origin.y = resultRect.origin.y;
remainingRect.size.height = resultRect.size.height;
remainingRect.size.width = _size.width - (resultRect.origin.x + resultRect.size.width);
}
return resultRect;
}
@end
var CPTextContainerSizeKey = @"CPTextContainerSizeKey",
CPTextContainerLayoutManagerKey = @"CPTextContainerLayoutManagerKey";
@implementation CPTextContainer (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
[self _init];
_size = [aCoder decodeSizeForKey:CPTextContainerSizeKey];
_layoutManager = [aCoder decodeObjectForKey:CPTextContainerLayoutManagerKey];
[_layoutManager addTextContainer:self];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeSize:_size forKey:CPTextContainerSizeKey];
[aCoder encodeObject:_layoutManager forKey:CPTextContainerLayoutManagerKey];
}
@end
+303
View File
@@ -0,0 +1,303 @@
/*
* CPTextStorage.j
* AppKit
*
* Created by Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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/CPNotificationCenter.j>
@import <Foundation/CPAttributedString.j>
@import "CPText.j"
@import "CPFont.j"
@class CPLayoutManager;
CPTextStorageEditedAttributes = 1;
CPTextStorageEditedCharacters = 2;
CPTextStorageWillProcessEditingNotification = @"CPTextStorageWillProcessEditingNotification";
CPTextStorageDidProcessEditingNotification = @"CPTextStorageDidProcessEditingNotification";
@protocol CPTextStorageDelegate <CPObject>
- (void)textStorageWillProcessEditing:(CPNotification)aNotification;
- (void)textStorageDidProcessEditing:(CPNotification)aNotification;
@end
var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
CPTextStorageDelegate_textStorageDidProcessEditing_ = 1 << 2;
/*!
@ingroup appkit
@class CPTextStorage
*/
@implementation CPTextStorage : CPMutableAttributedString
{
CPColor _foregroundColor @accessors(property=foregroundColor);
CPFont _font @accessors(property=font);
CPMutableArray _layoutManagers @accessors(getter=layoutManagers);
CPRange _editedRange @accessors(getter=editedRange);
id <CPTextStorageDelegate> _delegate @accessors(property=delegate);
int _changeInLength @accessors(property=changeInLength);
unsigned _editedMask @accessors(property=editedMask);
int _editCount; // {begin,end}Editing counter
unsigned _implementedDelegateMethods;
}
#pragma mark -
#pragma mark Init methods
- (id)initWithString:(CPString)aString attributes:(CPDictionary)attributes
{
self = [super initWithString:aString attributes:attributes];
if (self)
{
_layoutManagers = [[CPMutableArray alloc] init];
_editedRange = CPMakeRange(CPNotFound, 0);
_changeInLength = 0;
_editedMask = 0;
}
return self;
}
- (id)initWithString:(CPString)aString
{
return [self initWithString:aString attributes:nil];
}
- (id)init
{
return [self initWithString:@"" attributes:nil];
}
#pragma mark -
#pragma mark Delegate methods
- (void)setDelegate:(id <CPTextStorageDelegate>)aDelegate
{
if (_delegate === aDelegate)
return;
_implementedDelegateMethods = 0;
_delegate = aDelegate;
if (_delegate)
{
if ([_delegate respondsToSelector:@selector(textStorageWillProcessEditing:)])
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageWillProcessEditing_;
if ([_delegate respondsToSelector:@selector(textStorageDidProcessEditing:)])
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageDidProcessEditing_;
}
}
#pragma mark -
#pragma mark Layout manager methods
- (void)addLayoutManager:(CPLayoutManager)aManager
{
if ([_layoutManagers containsObject:aManager])
return
[aManager setTextStorage:self];
[_layoutManagers addObject:aManager];
}
- (void)removeLayoutManager:(CPLayoutManager)aManager
{
if (![_layoutManagers containsObject:aManager])
return
[aManager setTextStorage:nil];
[_layoutManagers removeObject:aManager];
}
- (void)invalidateAttributesInRange:(CPRange)aRange
{
/* FIXME: stub */
}
#pragma mark -
#pragma mark Editing methods
- (void)processEditing
{
[self _sendDelegateWillProcessEditingNotification];
[self invalidateAttributesInRange:[self editedRange]];
[self _sendDelegateDidProcessEditingNotification];
var c = [_layoutManagers count];
for (var i = 0; i < c; i++)
{
[[_layoutManagers objectAtIndex:i] textStorage:self
edited:_editedMask
range:_editedRange
changeInLength:_changeInLength
invalidatedRange:_editedRange];
}
_editedRange.location = CPNotFound;
_editedMask = 0;
_changeInLength = 0;
}
- (void)beginEditing
{
if (_editCount == 0)
_editedRange = CPMakeRange(CPNotFound, 0);
_editCount++;
}
- (void)endEditing
{
_editCount--;
if (_editCount == 0)
[self processEditing];
}
- (void)edited:(unsigned)editedMask range:(CPRange)aRange changeInLength:(int)lengthChange
{
var copyRange = CPMakeRangeCopy(aRange);
if (_editCount == 0) // used outside a beginEditing/endEditing
{
_editedMask = editedMask;
_changeInLength = lengthChange;
copyRange.length += lengthChange;
_editedRange = copyRange;
[self processEditing];
}
else
{
_editedMask |= editedMask;
_changeInLength += lengthChange;
copyRange.length += lengthChange;
if (_editedRange.location == CPNotFound)
_editedRange = copyRange;
else
_editedRange = CPUnionRange(_editedRange,copyRange);
}
}
- (void)removeAttribute:(CPString)anAttribute range:(CPRange)aRange
{
[self beginEditing];
[super removeAttribute:anAttribute range:aRange];
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
[self endEditing];
}
- (void)addAttributes:(CPDictionary)aDictionary range:(CPRange)aRange
{
[self beginEditing];
[super addAttributes:aDictionary range:aRange];
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
[self endEditing];
}
- (void)deleteCharactersInRange:(CPRange)aRange
{
[self beginEditing];
[super deleteCharactersInRange:aRange];
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:-aRange.length];
[self endEditing];
}
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
{
[self beginEditing];
[super replaceCharactersInRange:aRange withString:aString];
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:([aString length] - aRange.length)];
[self endEditing];
}
- (void)replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPAttributedString)aString
{
[self beginEditing];
[super replaceCharactersInRange:aRange withAttributedString:aString];
[self edited:(CPTextStorageEditedAttributes | CPTextStorageEditedCharacters) range:aRange changeInLength:([aString length] - aRange.length)];
[self endEditing];
}
- (CPAttributedString)attributedSubstringFromRange:(CPRange)aRange
{
if (!aRange.length)
return [CPAttributedString new];
return [super attributedSubstringFromRange:aRange];
}
@end
@implementation CPTextStorage (CPTextStorageDelegate)
- (void)_sendDelegateWillProcessEditingNotification
{
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageWillProcessEditing_)
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageWillProcessEditingNotification object:self userInfo:nil]];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageWillProcessEditingNotification object:self];
}
- (void)_sendDelegateDidProcessEditingNotification
{
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageDidProcessEditing_)
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageDidProcessEditingNotification object:self userInfo:nil]];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageDidProcessEditingNotification object:self];
}
@end
@implementation CPTextStorage (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
}
@end
File diff suppressed because it is too large Load Diff
+430
View File
@@ -0,0 +1,430 @@
/*
* CPTypesetter.j
* AppKit
*
* Created by Daniel Boehringer on 27/12/2013.
* All modifications copyright Daniel Boehringer 2013.
* Extensive code formatting and review by Andrew Hankinson
* Based on original work by
* Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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 "CPParagraphStyle.j"
@import "CPTextStorage.j"
@import "CPFont.j"
// forward declare these classes for type matching
@class CPLayoutManager
@class CPTextContainer
@class CPTextView
/*
CPTypesetterControlCharacterAction
*/
CPTypesetterZeroAdvancementAction = 1 << 0;
CPTypesetterWhitespaceAction = 1 << 1;
CPSTypesetterHorizontalTabAction = 1 << 2;
CPTypesetterLineBreakAction = 1 << 3;
CPTypesetterParagraphBreakAction = 1 << 4;
CPTypesetterContainerBreakAction = 1 << 5;
var CPSystemTypesetterFactory,
_sharedSimpleTypesetter;
@implementation CPTypesetter : CPObject
#pragma mark -
#pragma mark Class methods
+ (void)initialize
{
[CPTypesetter _setSystemTypesetterFactory:[CPSimpleTypesetter class]];
}
+ (id)sharedSystemTypesetter
{
return [CPSystemTypesetterFactory sharedInstance];
}
+ (void)_setSystemTypesetterFactory:(Class)aClass
{
CPSystemTypesetterFactory = aClass;
}
- (CPTypesetterControlCharacterAction)actionForControlCharacterAtIndex:(unsigned)charIndex
{
return CPTypesetterZeroAdvancementAction;
}
- (CPLayoutManager)layoutManager
{
return nil;
}
- (CPTextContainer)currentTextContainer
{
return nil;
}
- (CPArray)textContainers
{
return nil;
}
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
startingAtGlyphIndex:(unsigned)startGlyphIndex
maxNumberOfLineFragments:(unsigned)maxNumLines
nextGlyphIndex:(UIntegerReference)nextGlyph
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
@end
@implementation CPSimpleTypesetter : CPTypesetter
{
CPLayoutManager _layoutManager @accessors(property=layoutManager);
CPTextContainer _currentTextContainer @accessors(property=currentTextContainer);
CPTextStorage _textStorage;
CPRange _attributesRange;
CPDictionary _currentAttributes;
CPParagraphStyle _currentParagraph;
float _lineHeight;
float _lineBase;
float _lineWidth;
unsigned _indexOfCurrentContainer;
CPArray _lineFragments;
}
#pragma mark -
#pragma mark Class methods
+ (id)sharedInstance
{
if (!_sharedSimpleTypesetter)
_sharedSimpleTypesetter = [[CPSimpleTypesetter alloc] init];
return _sharedSimpleTypesetter;
}
- (CPArray)textContainers
{
return [_layoutManager textContainers];
}
- (CPTextTab)textTabForWidth:(double)aWidth writingDirection:(CPWritingDirection)direction
{
var tabStops = [_currentParagraph tabStops];
if (!tabStops)
tabStops = [CPParagraphStyle _defaultTabStops];
var l = tabStops.length;
if (aWidth > tabStops[l - 1]._location)
return nil;
for (var i = l - 1; i >= 0; i--)
{
if (aWidth > tabStops[i]._location)
{
if (i + 1 < l)
return tabStops[i + 1];
}
}
if (i === -1)
return tabStops[0];
return nil;
}
- (BOOL)_flushRange:(CPRange)lineRange
lineOrigin:(CGPoint)lineOrigin
currentContainer:(CPTextContainer)aContainer
advancements:(CPArray)advancements
lineCount:(unsigned)lineCount
sameLine:(BOOL)sameLine
{
var myX = 0,
rect = CGRectMake(lineOrigin.x, lineOrigin.y, _lineWidth, _lineHeight),
containerSize = aContainer._size;
[_layoutManager _appendNewLineFragmentInTextContainer:_currentTextContainer forGlyphRange:lineRange]
var fragment = [_layoutManager._lineFragments lastObject];
fragment._isLast = !sameLine;
_lineFragments.push(fragment);
[_layoutManager setLineFragmentRect:rect forGlyphRange:lineRange usedRect:rect];
switch ([_currentParagraph alignment])
{
case CPLeftTextAlignment:
myX = 0;
break;
case CPCenterTextAlignment:
myX = (containerSize.width - _lineWidth) / 2;
break;
case CPRightTextAlignment:
myX = containerSize.width - _lineWidth;
break;
}
[_layoutManager setLocation:CGPointMake(myX, _lineBase) forStartOfGlyphRange:lineRange];
[_layoutManager _setAdvancements:advancements forGlyphRange:lineRange];
if (!sameLine) //fix the _lineFragments when fontsizes differ
{
var l = _lineFragments.length;
for (var i = 0 ; i < l ; i++)
[_lineFragments[i] _adjustForHeight:_lineHeight];
}
if (!lineCount) // do not rescue on first line
return NO;
if (aContainer._inResizing)
return NO;
return ([_layoutManager _rescuingInvalidFragmentsWasPossibleForGlyphRange:lineRange]);
}
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
startingAtGlyphIndex:(unsigned)glyphIndex
maxNumberOfLineFragments:(unsigned)maxNumLines
nextGlyphIndex:(UIntegerReference)nextGlyph
{
var textContainers = [layoutManager textContainers],
textContainersCount = [textContainers count];
_layoutManager = layoutManager;
_textStorage = [_layoutManager textStorage];
_indexOfCurrentContainer = MAX(0, [textContainers
indexOfObject:[_layoutManager textContainerForGlyphAtIndex:glyphIndex effectiveRange:nil withoutAdditionalLayout:YES]
inRange:CPMakeRange(0, textContainersCount)]);
_currentTextContainer = textContainers[_indexOfCurrentContainer];
_attributesRange = CPMakeRange(0, 0);
_lineHeight = 0;
_lineBase = 0;
_lineWidth = 0;
var containerSize = [_currentTextContainer containerSize],
containerSizeWidth = containerSize.width,
containerSizeHeight = containerSize.height,
lineRange = CPMakeRange(glyphIndex, 0),
wrapRange = CPMakeRange(0, 0),
wrapWidth = 0,
isNewline = NO,
isTabStop = NO,
isWordWrapped = NO,
numberOfGlyphs= [_textStorage length],
leading,
numLines = 0,
theString = [_textStorage string],
lineOrigin,
ascent,
descent,
advancements = [],
prevRangeWidth = 0,
measuringRange = CPMakeRange(glyphIndex, 0),
currentAnchor = 0,
currentFont,
currentFontLineHeight,
previousFont,
currentParagraphMinimumLineHeight,
currentParagraphMaximumLineHeight,
currentParagraphLineSpacing;
if (glyphIndex > 0)
lineOrigin = CGPointCreateCopy([_layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:nil].origin);
else if ([_layoutManager extraLineFragmentTextContainer])
lineOrigin = CGPointMake(0, [_layoutManager extraLineFragmentUsedRect].origin.y);
else
lineOrigin = CGPointMake(0, 0);
[_layoutManager _removeInvalidLineFragments];
if (![_textStorage length])
return;
_lineFragments = [];
for (; numLines != maxNumLines && glyphIndex < numberOfGlyphs; glyphIndex++)
{
// check whether there any change in the attributes from here on
if (!CPLocationInRange(glyphIndex, _attributesRange))
{
_currentAttributes = [_textStorage attributesAtIndex:glyphIndex effectiveRange:_attributesRange];
currentFont = [_currentAttributes objectForKey:CPFontAttributeName];
_currentParagraph = [_currentAttributes objectForKey:CPParagraphStyleAttributeName] || [CPParagraphStyle defaultParagraphStyle];
currentParagraphMinimumLineHeight = [_currentParagraph minimumLineHeight];
currentParagraphMaximumLineHeight = [_currentParagraph maximumLineHeight];
currentParagraphLineSpacing = [_currentParagraph lineSpacing];
if (!currentFont)
currentFont = [_textStorage font] || [CPFont systemFontOfSize:12.0];
ascent = [currentFont ascender]
descent = [currentFont descender]
leading = (ascent - descent) * 0.2; // FAKE leading
currentFontLineHeight = ascent - descent + leading;
if (previousFont !== currentFont)
{
measuringRange = CPMakeRange(glyphIndex, 0);
currentAnchor = prevRangeWidth;
previousFont = currentFont;
}
}
if (currentFontLineHeight > _lineHeight)
_lineHeight = currentFontLineHeight;
if (ascent > _lineBase)
_lineBase = ascent;
lineRange.length++;
measuringRange.length++;
var currentCharCode = theString.charCodeAt(glyphIndex), // use pure javascript methods for performance reasons
rangeWidth = [theString.substr(measuringRange.location, measuringRange.length) sizeWithFont:currentFont inWidth:NULL].width + currentAnchor;
switch (currentCharCode) // faster than sending actionForControlCharacterAtIndex: called for each char.
{
case 9: // '\t'
{
var nextTab = [self textTabForWidth:rangeWidth + lineOrigin.x writingDirection:0];
isTabStop = YES;
if (nextTab)
rangeWidth = nextTab._location - lineOrigin.x;
else
rangeWidth += 28; //FIXME
} // fallthrough intentional
case 32: // ' '
wrapRange = CPMakeRangeCopy(lineRange);
wrapWidth = rangeWidth;
wrapRange._height = _lineHeight;
wrapRange._base = _lineBase;
break;
case 10:
case 13:
isNewline = YES;
}
advancements.push({width: rangeWidth - prevRangeWidth, height: ascent, descent: descent});
prevRangeWidth = _lineWidth = rangeWidth;
if (lineOrigin.x + rangeWidth > containerSizeWidth)
{
if (wrapWidth)
{
lineRange = wrapRange;
_lineWidth = wrapWidth;
_lineHeight = wrapRange._height;
_lineBase = wrapRange._base;
}
isNewline = YES;
isWordWrapped = YES;
glyphIndex = CPMaxRange(lineRange) - 1; // start the line starts directly at current character
}
if (isNewline || isTabStop)
{
if ([self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:!isNewline])
return;
if (isTabStop)
{
lineOrigin.x += rangeWidth;
isTabStop = NO;
}
if (isNewline)
{
if (currentParagraphMinimumLineHeight && currentParagraphMinimumLineHeight > _lineHeight)
_lineHeight = currentParagraphMinimumLineHeight;
if (currentParagraphMaximumLineHeight && currentParagraphMaximumLineHeight < _lineHeight)
_lineHeight = currentParagraphMaximumLineHeight;
lineOrigin.y += _lineHeight;
if (currentParagraphLineSpacing)
lineOrigin.y += currentParagraphLineSpacing;
if (lineOrigin.y > containerSizeHeight && _indexOfCurrentContainer < textContainersCount - 1)
{
_currentTextContainer = textContainers[++_indexOfCurrentContainer];
containerSize = [_currentTextContainer containerSize];
containerSizeWidth = containerSize.width;
containerSizeHeight = containerSize.height;
}
lineOrigin.x = 0;
numLines++;
isNewline = NO;
_lineFragments = [];
_lineHeight = 0;
_lineBase = ascent;
}
_lineWidth = 0;
advancements = [];
currentAnchor = 0;
prevRangeWidth = 0;
lineRange = CPMakeRange(glyphIndex + 1, 0);
measuringRange = CPMakeRange(glyphIndex + 1, 0);
wrapRange = CPMakeRange(0, 0);
wrapWidth = 0;
isWordWrapped = NO;
}
}
// this is to "flush" the remaining characters
if (lineRange.length)
{
[self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:NO];
}
var rect = CGRectMake(0, lineOrigin.y, containerSizeWidth, [_layoutManager._lineFragments lastObject]._usedRect.size.height - descent);
[_layoutManager setExtraLineFragmentRect:rect usedRect:rect textContainer:_currentTextContainer];
}
@end
+788
View File
@@ -0,0 +1,788 @@
/* RTFParser.j
Parse a RTF string into a CPAttributedString
Copyright (C) 2014 Daniel Boehringer
FIXME: this class should be redone using a 'real' parser
* all paragraph spacing information is currently not parsed
* 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/CPAttributedString.j>
@import <Foundation/CPGeometry.j>
@import "CPFontManager.j"
@import "CPParagraphStyle.j"
@global CPLeftTextAlignment
@global CPRightTextAlignment
@global CPCenterTextAlignment
@global CPJustifiedTextAlignment
@global CPNaturalTextAlignment
@global CPFontAttributeName
@global CPForegroundColorAttributeName
var hexTable = [];
// Hold the attributes of the current run
@implementation _RTFAttribute : CPObject
{
CPRange _range;
CPParagraphStyle paragraph;
CPColor fgColour;
CPColor bgColour;
CPColor ulColour;
CPString fontName;
unsigned fontSize;
BOOL bold;
BOOL italic;
BOOL underline;
BOOL strikethrough;
BOOL script;
BOOL _tabChanged;
}
- (id)init
{
if (self = [super init])
{
[self resetFont];
[self resetParagraphStyle];
_range = CPMakeRange(0, 0);
}
return self;
}
- (id)copy
{
var mynew = [_RTFAttribute new];
mynew.paragraph = [paragraph copy];
mynew.fontName = fontName;
mynew.fgColour = fgColour;
mynew.bgColour = bgColour;
mynew.ulColour = ulColour;
return mynew;
}
- (CPFont)currentFont
{
var font = [CPFont _fontWithName:fontName size:fontSize bold:bold italic:italic];
if (font)
return font;
//Before giving up and using a default font, we try if this is
//not the case of a font with a composite name, such as
//'Helvetica-Light'. In that case, even if we don't have
//exactly an 'Helvetica-Light' font family, we might have an
//'Helvetica' one.
var range = [fontName rangeOfString:@"-"];
if (range.location != CPNotFound)
{
var fontFamily = [fontName substringToIndex: range.location];
font = [CPFont fontWithName:fontFamily size:fontSize];
}
/* Last resort, default font. :-( */
if (font == nil)
font = [CPFont systemFontOfSize:fontSize];
return font;
}
- (CPNumber)script
{
return [CPNumber numberWithInt: script];
}
- (CPNumber)underline
{
if (underline != 0)
return [CPNumber numberWithInteger: underline];
else
return nil;
}
- (CPNumber)strikethrough
{
if (strikethrough != 0)
return [CPNumber numberWithInteger: strikethrough];
else
return nil;
}
- (void)resetParagraphStyle
{
paragraph = [[CPParagraphStyle defaultParagraphStyle] copy];
}
- (void)resetFont
{
var font = [CPFont systemFontOfSize:12];
fontName = [font familyName];
fontSize = 12.0;
italic = NO;
bold = NO;
underline = 0;
strikethrough = 0;
script = 0;
}
- (void)addTab:(float)location type:(CPTextTabType)type
{
var tab = [[CPTextTab alloc] initWithType:CPLeftTabStopType
location:location];
if (!_tabChanged)
{
[paragraph setTabStops:[tab]];
_tabChanged = YES;
}
else
{
[paragraph addTabStop: tab];
}
}
- (CPDictionary)dictionary
{
var ret = @{};
[ret setObject:[self currentFont] forKey:CPFontAttributeName];
[ret setObject:paragraph forKey:CPParagraphStyleAttributeName];
if (fgColour)
[ret setObject:fgColour forKey:CPForegroundColorAttributeName];
return ret;
}
@end
// based on https://github.com/lazygyu/RTF-parser
var kRTFParserType_char = 0,
kRTFParserType_dest = 1,
kRTFParserType_prop = 2,
kRTFParserType_spec = 3;
// Keyword descriptions
var kRgsymRtf = {
// keyword dflt fPassDflt kwd idx
"b" : [ "b", 1, false, kRTFParserType_prop, "propBold"],
"ul" : [ "ul", 1, false, kRTFParserType_prop, "propUnderline"],
"i" : [ "i", 1, false, kRTFParserType_prop, "propItalic"],
"li" : [ "li", 0, false, kRTFParserType_prop, "propPgnFormat"],
"pgnucltr" : [ "pgnucltr", "pgULtr", true, kRTFParserType_prop, "propPgnFormat"],
"pgnlcltr" : [ "pgnlcltr", "pgLLtr", true, kRTFParserType_prop, "propPgnFormat"],
"qc" : [ "qc", "justC", true, kRTFParserType_prop, "propJust"],
"ql" : [ "ql", "justL", true, kRTFParserType_prop, "propJust"],
"qr" : [ "qr", "justR", true, kRTFParserType_prop, "propJust"],
"qj" : [ "qj", "justF", true, kRTFParserType_prop, "propJust"],
"paperw" : [ "paperw", 12240, false, kRTFParserType_prop, "propXaPage"],
"paperh" : [ "paperh", 15480, false, kRTFParserType_prop, "propYaPage"],
"margl" : [ "margl", 1800, false, kRTFParserType_prop, "propXaLeft"],
"margr" : [ "margr", 1800, false, kRTFParserType_prop, "propXaRight"],
"margt" : [ "margt", 1440, false, kRTFParserType_prop, "propYaTop"],
"margb" : [ "margb", 1440, false, kRTFParserType_prop, "propYaBottom"],
"pgnstart" : [ "pgnstart", 1, true, kRTFParserType_prop, "propPgnStart"],
"facingp" : [ "facingp", 1, true, kRTFParserType_prop, "propFacingp"],
"landscape" : [ "landscape",1, true, kRTFParserType_prop, "propLandscape"],
"par" : [ "par", 0, false, kRTFParserType_char, "\n"],
"pard" : [ "pard", 0, false, kRTFParserType_prop, "propDefaultPara"],
"\0x0a" : [ "\0x0a", 0, false, kRTFParserType_char, "\n"],
"\0x0d" : [ "\0x0d", 0, false, kRTFParserType_char, ""],
"tab" : [ "tab", 0, false, kRTFParserType_char, "\t"],
"ldblquote" : [ "ldblquote",0, false, kRTFParserType_char, '"'],
"rdblquote" : [ "rdblquote",0, false, kRTFParserType_char, '"'],
"bin" : [ "bin", 0, false, kRTFParserType_spec, "ipfnBin"],
"*" : [ "*", 0, false, kRTFParserType_spec, "ipfnDestSkip"],
"'" : [ "'", 0, false, kRTFParserType_spec, "ipfnHex"],
"author" : [ "author", 0, false, kRTFParserType_dest, "destSkip"],
"buptim" : [ "buptim", 0, false, kRTFParserType_dest, "destSkip"],
"colortbl" : [ "colortbl", 0, false, kRTFParserType_dest, "destSkip"],
"comment" : [ "comment", 0, false, kRTFParserType_dest, "destSkip"],
"creatim" : [ "creatim", 0, false, kRTFParserType_dest, "destSkip"],
"doccomm" : [ "doccomm", 0, false, kRTFParserType_dest, "destSkip"],
"fonttbl" : [ "fonttbl", 0, false, kRTFParserType_dest, "destSkip"],
"footer" : [ "footer", 0, false, kRTFParserType_dest, "destSkip"],
"footerf" : [ "footerf", 0, false, kRTFParserType_dest, "destSkip"],
"footerl" : [ "footerl", 0, false, kRTFParserType_dest, "destSkip"],
"footerr" : [ "footerr", 0, false, kRTFParserType_dest, "destSkip"],
"footnote" : [ "footnote", 0, false, kRTFParserType_dest, "destSkip"],
"ftncn" : [ "ftncn", 0, false, kRTFParserType_dest, "destSkip"],
"ftnsep" : [ "ftnsep", 0, false, kRTFParserType_dest, "destSkip"],
"ftnsepc" : [ "ftnsepc", 0, false, kRTFParserType_dest, "destSkip"],
"fprq" : [ "fprq", 0, false, kRTFParserType_dest, "destSkip"],
// "fcharset" : [ "fcharset", 0, false, kRTFParserType_dest, "destSkip"],
"rquote" : [ "rquote", 0, false, kRTFParserType_char, "'"],
// "s" : [ "s", 0, false, kRTFParserType_dest, "destSkip"],
"header" : [ "header", 0, false, kRTFParserType_dest, "destSkip"],
"headerf" : [ "headerf", 0, false, kRTFParserType_dest, "destSkip"],
"headerl" : [ "headerl", 0, false, kRTFParserType_dest, "destSkip"],
"headerr" : [ "headerr", 0, false, kRTFParserType_dest, "destSkip"],
"info" : [ "info", 0, false, kRTFParserType_dest, "destSkip"],
"keywords" : [ "keywords", 0, false, kRTFParserType_dest, "destSkip"],
"operator" : [ "operator", 0, false, kRTFParserType_dest, "destSkip"],
"pict" : [ "pict", 0, false, kRTFParserType_dest, "destSkip"],
"printim" : [ "printim", 0, false, kRTFParserType_dest, "destSkip"],
"private1" : [ "private1", 0, false, kRTFParserType_dest, "destSkip"],
"revtim" : [ "revtim", 0, false, kRTFParserType_dest, "destSkip"],
"rxe" : [ "rxe", 0, false, kRTFParserType_dest, "destSkip"],
"stylesheet" : [ "stylesheet",0, false, kRTFParserType_dest, "destSkip"],
"subject" : [ "subject", 0, false, kRTFParserType_dest, "destSkip"],
"tc" : [ "tc", 0, false, kRTFParserType_dest, "destSkip"],
"title" : [ "title", 0, false, kRTFParserType_dest, "destSkip"],
"txe" : [ "txe", 0, false, kRTFParserType_dest, "destSkip"],
"xe" : [ "xe", 0, false, kRTFParserType_dest, "destSkip"],
"[" : [ "[", 0, false, kRTFParserType_char, '['],
" " : [ " ", 0, false, kRTFParserType_char, ' '],
"]" : [ "]", 0, false, kRTFParserType_char, ']'],
"{" : [ "{", 0, false, kRTFParserType_char, '{'],
"}" : [ "}", 0, false, kRTFParserType_char, '}'],
"\\" : [ "\\", 0, false, kRTFParserType_char, '\\']
};
@implementation _CPRTFParser : CPObject
{
CPString _codePage;
CGSize _paper;
CPString _rtf;
unsigned _curState;
CPArray _states;
unsigned _currentParseIndex;
BOOL _hexreturn;
_RTFAttribute _currentRun;
CPAttributedString _result;
CPArray _colorArray;
CPArray _fontArray;
CPString _freename;
BOOL _parsingFontTable;
}
- (id)init
{
if (self = [super init])
{
_paper = CPMakeSize(0, 0);
_rtf = "";
_curState = 0; // 0 = normal, 1 = skip
_states = [];
_currentParseIndex = 0;
_hexreturn = NO;
_result = [CPAttributedString new];
_colorArray = [];
_fontArray = ['Arial']; // FIXME: should be name of system font
_freename = "";
_parsingFontTable = NO;
}
return self;
}
- (CPString)_checkChar:(CPArray)sym parameter:(CPString)ch
{
switch (_curState)
{
case 0:
if (sym && sym[4])
return sym[4];
case 1:
// CPLogConsole("skipped : " + sym[4]);
return '';
default:
if (sym && sym[4])
return sym[4];
}
}
- (BOOL)pushState
{
_states.push["group"];
return YES;
}
- (BOOL)popState
{
_states.pop();
if (_curState > 0)
_curState--;
return YES;
}
- (CPString)_parseSpec:(CPArray)sym parameter:(CPString)v
{
var ch = '';
switch (sym[4])
{
case "ipfnDestSkip":
_curState++;
return '';
case "ipfnHex":
ch = _rtf.charAt(++_currentParseIndex);
var hex = '';
while (/[a-fA-F0-9\']/.test(ch))
{
if (ch == "'")
{
_currentParseIndex++;
continue;
}
hex += (ch + '');
ch = _rtf.charAt(++_currentParseIndex);
}
//ch = parseInt(ch, 16);
//console.log("hex : " + hex);
_hexreturn = YES;
_currentParseIndex--;
if (_curState !== 0)
return '';
else
return hex;
break;
case "codePage":
ch = _rtf.charAt(++_currentParseIndex);
var code = '';
while (/[0-9]/.test(ch))
{
code += (ch + '');
ch = _rtf.charAt(++_currentParseIndex);
}
_codePage = code;
_currentParseIndex--;
break;
}
return '';
}
- (void)_flushCurrentRun
{
var newOffset = 0;
if (_currentRun)
{
if ([_result length] == _currentRun._range.location)
return;
_currentRun._range.length = [_result length] - _currentRun._range.location;
newOffset = CPMaxRange(_currentRun._range);
var dict = [_currentRun dictionary];
[_result setAttributes:dict range:_currentRun._range]; // flush previous run
_currentRun.fgColour = [CPColor blackColor];
}
else
_currentRun = [_RTFAttribute new];
_currentRun._range = CPMakeRange(newOffset, 0); // open a new one
}
- (CPString)_applyPropChange:sym parameter:param
{
//console.log("prop : " + sym[0] + " / param : " + param+ ' ');
switch (sym[0])
{
case "pard":
[self _flushCurrentRun];
break;
case "b": // bold
if (param === 0)
{
if (_currentRun && _currentRun.bold)
[self _flushCurrentRun];
_currentRun.bold = NO
}
else
{
if (_currentRun && !_currentRun.bold)
[self _flushCurrentRun];
_currentRun.bold = YES;
}
break;
case "i": // italic
if (param === 0)
{
if (_currentRun && _currentRun.italic)
[self _flushCurrentRun];
_currentRun.italic = NO
}
else
{
if (_currentRun && !_currentRun.italic)
[self _flushCurrentRun];
_currentRun.italic = YES;
}
break;
case "qc": // paragraph center
[_currentRun.paragraph setAlignment:CPCenterTextAlignment];
break;
case "paperw":
_paper.width = param;
break;
case "paperh":
_paper.height = param;
break;
}
return '';
}
- (CPString)_changeDest:(CPArray)sym
{
switch (sym[0])
{
case "colortbl":
_colorArray.push([CPColor blackColor]);
break;
case "fonttbl":
_parsingFontTable = YES;
break;
}
if (sym[4] == "destSkip")
{
CPLogConsole("Dest skip start : [" + sym[0] + "]");
_curState++;
}
return '';
}
- (CPString)_translateKeyword:(CPString)keyword parameter:(CPString)param fParameter:(BOOL)fParam
{
if (kRgsymRtf[keyword] !== undefined)
{
var sym = kRgsymRtf[keyword];
switch (sym[3])
{
case kRTFParserType_prop:
if (sym[2] || !fParam)
param = sym[1];
return [self _applyPropChange:sym parameter:param];
case kRTFParserType_char:
return [self _checkChar:sym parameter:param];
case kRTFParserType_dest:
return [self _changeDest:sym];
case kRTFParserType_spec:
return [self _parseSpec:sym parameter:param];
default:
return '';
}
}
else
{
switch (keyword)
{
case "red":
var oldColor = [_colorArray lastObject],
green = [oldColor greenComponent],
blue = [oldColor blueComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:parseInt(param) / 255 green:green blue:blue alpha:1.0]);
break;
case "green":
var oldColor = [_colorArray lastObject],
red = [oldColor redComponent],
blue = [oldColor blueComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:red green: parseInt(param) / 255 blue:blue alpha:1.0]);
break;
case "blue":
var oldColor = [_colorArray lastObject],
green = [oldColor greenComponent],
red = [oldColor redComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:red green:green blue:parseInt(param) / 255 alpha:1.0]);
_colorArray.push([CPColor blackColor]); // placeholder for next color
break;
case "cf": // change foreground color
[self _flushCurrentRun];
var fontIndex = parseInt(param) - 1;
if (_currentRun && fontIndex >= 0)
_currentRun.fgColour = _colorArray[fontIndex];
break;
case "f": // change font
[self _flushCurrentRun];
var fontIndex = parseInt(param);
if (_currentRun && fontIndex >= 0 && fontIndex < _fontArray.length)
_currentRun.fontName = _fontArray[fontIndex];
break;
case "fs": // change font size
[self _flushCurrentRun];
_currentRun.fontSize = parseInt(param) / 2;
break;
case "tx": // tabstop
var location = parseInt(param) / 20;
if (_currentRun)
[_currentRun addTab:location type:CPLeftTabStopType];
break;
default:
CPLogConsole("skip : " + keyword + " param: " + param);
}
if (_states.length > 0)
_curState = 1;
return '';
}
}
- (CPString)_parseKeyword:(CPString)rtf length:(unsigned)len
{
var ch = '',
fParam = false,
fNeg = false,
keyword = '',
param = '';
_rtf = rtf;
if (++_currentParseIndex >= len)
return len;
ch = rtf.charAt(_currentParseIndex);
if (!/[a-zA-Z]/.test(ch))
return [self _translateKeyword:ch parameter:nil fParameter:fParam];
while (/[a-zA-Z]/.test(ch))
{
keyword += ch;
ch = rtf.charAt(++_currentParseIndex);
}
if (ch == '-')
{
fNeg = true;
ch = rtf.charAt(++_currentParseIndex);
}
fParam = true;
while (/[0-9]/.test(ch))
{
param += (ch + '');
ch = rtf.charAt(++_currentParseIndex);
}
_currentParseIndex--;
param = parseInt(param);
if (fNeg)
param *= -1;
return [self _translateKeyword:keyword parameter:param fParameter:fParam];
}
- (void)_appendPlainString:(CPString) aString
{
[_result replaceCharactersInRange:CPMakeRange([_result length], 0) withString:aString];
}
- (CPAttributedString)parseRTF:(CPString)rtf
{
if (rtf.length == 0)
return '';
_currentParseIndex = -1;
var len = rtf.length,
tmp = '',
ch = '',
hex = '',
lastchar = 0;
while (_currentParseIndex < len)
{
tmp = rtf.charAt(++_currentParseIndex);
if (tmp !== "\\" && hex.length > 0)
{
[self _appendPlainString: String.fromCharCode(parseInt((hex), 16))];
hex = '';
}
switch (tmp)
{
case " ":
if (lastchar == 1)
{
lastchar = 0;
}
else
{
_freename += tmp;
[self _appendPlainString:tmp];
}
break;
case "{":
if ([self pushState])
CPLogConsole("push");
break;
case "}":
if ([self popState])
CPLogConsole("pop");
if (_freename)
{
CPLogConsole(_freename);
if (_parsingFontTable)
{
_fontArray.push(_freename);
_parsingFontTable = NO;
}
_freename = "";
}
[self _flushCurrentRun]
break;
case "\\":
_freename = '';
ch = [self _parseKeyword:rtf length:len];
if (!_hexreturn && ch.length == 0)
lastchar = 1;
else
lastchar = 0;
if (_hexreturn)
{
if (ch.length > 0)
{
if (parseInt(ch, 16) & 0x80)
{
hex += ch.toUpperCase();
}
else
{
[self _appendPlainString: String.fromCharCode(parseInt((hex + ch), 16))];
hex = '';
}
if (hex.length == 4)
{
var temp = parseInt(hex, 16);
if (hexTable && hexTable[hex.toUpperCase()] !== undefined)
temp = parseInt(hexTable[hex.toUpperCase()], 16);
[self _appendPlainString: String.fromCharCode(temp)]
hex = '';
}
}
else
{
CPLogConsole("hex skipped");
}
_hexreturn = NO;
}
else if (ch !== undefined && _curState === 0)
{
[self _appendPlainString:ch];
}
break;
case 0x0d:
case 0x0a:
case '\n':
case '\r':
break;
default:
lastchar = 0;
if (_curState == 0)
[self _appendPlainString:tmp];
else if (tmp !== ';')
_freename += tmp;
break;
}
}
return _result;
}
@end
+615
View File
@@ -0,0 +1,615 @@
/*
RTFProducer.j
Serialize CPAttributedString to a RTF String
Copyright (C) 2014 Daniel Boehringer
This file is based on the RTFProducer from GNUStep
(which i co-authored with Fred Kiefer in 1999)
* 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/CPAttributedString.j>
@import "CPParagraphStyle.j"
@import "CPColor.j"
@import "CPGraphics.j"
@import "CPFontManager.j"
@global CPForegroundColorAttributeName
@global CPBackgroundColorAttributeName
@global CPUnderlineStyleAttributeName
@global CPSuperscriptAttributeName
@global CPBaselineOffsetAttributeName
@global CPAttachmentAttributeName
@global CPLigatureAttributeName
@global CPKernAttributeName
@global CPLeftTextAlignment
@global CPRightTextAlignment
@global CPCenterTextAlignment
@global CPJustifiedTextAlignment
@global CPNaturalTextAlignment
var PAPERSIZE = @"PaperSize",
LEFTMARGIN = @"LeftMargin",
RIGHTMARGIN = @"RightMargin",
TOPMARGIN = @"TopMargin",
BUTTOMMARGIN = @"ButtomMargin";
function _points2twips(a) { return (a) * 20.0; }
@implementation _CPRTFProducer : CPObject
{
CPAttributedString text;
CPMutableDictionary fontDict;
CPMutableDictionary colorDict;
CPDictionary docDict;
CPMutableArray attachments;
CPFont currentFont;
CPColor fgColor;
CPColor bgColor;
CPColor ulColor;
}
#pragma mark -
#pragma mark Class methods
+ (CPString)produceRTF:(CPAttributedString)aText documentAttributes:(CPDictionary)dict
{
var mynew = [self new];
return [mynew RTFDStringFromAttributedString:aText documentAttributes:dict];
}
#pragma mark -
#pragma mark init methods
- (id)init
{
if (self = [super init])
{
// maintain a dictionary for the used colours
// (for rtf-header generation)
colorDict = [CPMutableDictionary new];
//maintain a dictionary for the used fonts
//(for rtf-header generation)
fontDict = [CPMutableDictionary new];
fgColor = [CPColor blackColor];
bgColor= [CPColor whiteColor];
}
return self;
}
// private stuff follows
- (CPString)fontTable
{
if (![fontDict count])
return @"";
var fontlistString = "",
fontEnum,
currFont,
keyArray;
keyArray = [fontDict allKeys];
keyArray = [keyArray sortedArrayUsingSelector:@selector(compare:)];
fontEnum = [keyArray objectEnumerator];
while ((currFont = [fontEnum nextObject]) !== nil)
{
var fontFamily,
detail;
if ([currFont isEqualToString:@"Symbol"])
fontFamily = @"tech";
else if ([currFont isEqualToString:@"Helvetica"])
fontFamily = @"swiss";
else if ([currFont isEqualToString:@"Arial"])
fontFamily = @"swiss";
else if ([currFont isEqualToString:@"Courier"])
fontFamily = @"modern";
else if ([currFont isEqualToString:@"Times"])
fontFamily = @"roman";
else fontFamily = @"nil";
detail = [CPString stringWithFormat:@"%@\\f%@ %@;", [fontDict objectForKey:currFont], fontFamily, currFont];
fontlistString += detail;
}
return [CPString stringWithFormat:@"{\\fonttbl%@}\n", fontlistString];
}
- (CPString)colorTable
{
if (![colorDict count])
return @"";
var result,
count = [colorDict count],
list = [CPMutableArray arrayWithCapacity:count],
keyEnum = [colorDict keyEnumerator],
next,
i;
while ((next = [keyEnum nextObject]) !== nil)
{
var cn = [colorDict objectForKey:next];
[list insertObject:[CPColor colorWithCSSString:next] atIndex:[cn intValue]-1];
}
result = [CPString stringWithString:@"{\\colortbl;"];
for (i = 0; i < count; i++)
{
var color = [[list objectAtIndex:i]
colorUsingColorSpaceName:CPCalibratedRGBColorSpace];
result += [CPString stringWithFormat:@"\\red%d\\green%d\\blue%d;",
([color redComponent] * 255),
([color greenComponent] * 255),
([color blueComponent] * 255)];
}
result += @"}\n";
return result;
}
- (CPString)documentAttributes
{
if (!docDict)
return @"";
var result,
detail,
val,
num;
result = [CPString string];
val = [docDict objectForKey:PAPERSIZE];
if (val)
{
var size = [val sizeValue];
detail = [CPString stringWithFormat:@"\\paperw%d \\paperh%d",
_points2twips(size.width),
_points2twips(size.height)];
result += detail;
}
num = [docDict objectForKey:LEFTMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margl%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:RIGHTMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margr%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:TOPMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margt%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:BUTTOMMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margb%d", _points2twips(f)];
result += detail;
}
return result;
}
- (CPString)headerString
{
var result;
result = [CPString stringWithString:@"{\\rtf1\\ansi"];
result += [self fontTable];
result += [self colorTable];
result += [self documentAttributes];
return result;
}
- (CPString)trailerString
{
return @"}";
}
- (CPString)fontToken:(CPString) fontName
{
var fCount = [fontDict objectForKey:fontName];
if (fCount == nil)
{
var count = [fontDict count];
fCount = [CPString stringWithFormat:@"\\f%d", count];
[fontDict setObject:fCount forKey:fontName];
}
return fCount;
}
- (int)numberForColor:(CPColor)color
{
var num = [colorDict objectForKey:[color cssString]];
if (!num)
[colorDict setObject:num = [CPNumber numberWithInt:[colorDict count] + 1]
forKey:[color cssString]];
return [num intValue];
}
- (CPString)paragraphStyle:(CPParagraphStyle)paraStyle
{
var headerString = [CPString stringWithString:@"\\pard"],
twips;
if (paraStyle == nil)
return headerString;
switch ([paraStyle alignment])
{
case CPRightTextAlignment:
headerString += @"\\qr";
break;
case CPCenterTextAlignment:
headerString += @"\\qc";
break;
case CPLeftTextAlignment:
headerString += @"\\ql";
break;
case CPJustifiedTextAlignment:
headerString += @"\\qj";
break;
default:
headerString += @"\\ql";
break;
}
// write first line indent and left indent
var twips = _points2twips([paraStyle firstLineHeadIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\fi%d", twips];
twips = _points2twips([paraStyle headIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\li%d", twips];
twips = _points2twips([paraStyle tailIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\ri%d", twips];
twips = _points2twips([paraStyle paragraphSpacing]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sa%d", twips];
twips = _points2twips([paraStyle minimumLineHeight]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sl%d", twips];
twips = _points2twips([paraStyle maximumLineHeight]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sl-%d", twips];
var enumerator,
tab;
enumerator = [[paraStyle tabStops] objectEnumerator];
while ((tab = [enumerator nextObject]))
{
switch ([tab tabStopType])
{
case CPLeftTabStopType:
// no tabkind emission needed
break;
/* case NSRightTabStopType:
headerString += @"\\tqr";
break;
case NSCenterTabStopType:
headerString += @"\\tqc";
break;
case NSDecimalTabStopType:
headerString += @"\\tqdec";
break;
default:
NSLog(@"Unknown tab stop type.");
*/
}
headerString += [CPString stringWithFormat:@"\\tx%d",_points2twips([tab location])];
}
return headerString;
}
- (CPString)runStringForString:(CPString) substring
attributes:(CPDictionary) attributes
paragraphStart:(BOOL) first
{
var result = "",
headerString = "",
trailerString = "",
attribEnum,
currAttrib;
if (first)
{
var paraStyle = [attributes objectForKey:CPParagraphStyleAttributeName];
headerString += [self paragraphStyle:paraStyle];
}
/*
* analyze attributes of current run
*
* FIXME: All the character attributes should be output relative to the font
* attributes of the paragraph. So if the paragraph has underline on it should
* still be possible to switch it off for some characters, which currently is
* not possible.
*/
attribEnum = [attributes keyEnumerator];
while ((currAttrib = [attribEnum nextObject]) != nil)
{
if ([currAttrib isEqualToString:CPFontAttributeName])
{
/*
* handle fonts
*/
var font,
fontName,
traits;
font = [attributes objectForKey:CPFontAttributeName];
fontName = [font familyName];
traits = [[CPFontManager sharedFontManager] traitsOfFont:font];
/*
* font name
*/
if (currentFont == nil || ![fontName isEqualToString:[currentFont familyName]])
headerString += [self fontToken:fontName];
/*
* font size
*/
if (currentFont == nil || [font size] != [currentFont size])
{
var points = [font size] * 2,
pString;
pString = [CPString stringWithFormat:@"\\fs%d", points];
headerString += pString;
}
/*
* font attributes
*/
if (traits & CPItalicFontMask)
{
headerString += @"\\i";
trailerString += @"\\i0";
}
if (traits & CPBoldFontMask)
{
headerString += @"\\b";
trailerString += @"\\b0";
}
if (first)
currentFont = font;
}
else if ([currAttrib isEqualToString:CPForegroundColorAttributeName])
{
var color = [attributes objectForKey:CPForegroundColorAttributeName];
if (![color isEqual:fgColor])
{
headerString += [CPString stringWithFormat:@"\\cf%d", [self numberForColor:color]];
trailerString += @"\\cf0";
}
}
else if ([currAttrib isEqualToString:CPBackgroundColorAttributeName])
{
var color = [attributes objectForKey:CPBackgroundColorAttributeName];
if (![color isEqual:bgColor])
{
headerString += [CPString stringWithFormat:@"\\cb%d", [self numberForColor:color]];
trailerString += @"\\cb0";
}
}
else if ([currAttrib isEqualToString:CPUnderlineStyleAttributeName])
{
headerString += @"\\ul";
trailerString += @"\\ulnone";
}
else if ([currAttrib isEqualToString:CPSuperscriptAttributeName])
{
var value = [attributes objectForKey:CPSuperscriptAttributeName],
svalue = [value intValue] * 6;
if (svalue > 0)
{
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
trailerString += @"\\up0";
}
else if (svalue < 0)
{
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
trailerString += @"\\dn0";
}
}
else if ([currAttrib isEqualToString:CPBaselineOffsetAttributeName])
{
var value = [attributes objectForKey:CPBaselineOffsetAttributeName],
svalue = [value floatValue] * 2;
if (svalue > 0)
{
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
trailerString += @"\\up0";
}
else if (svalue < 0)
{
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
trailerString += @"\\dn0";
}
}
else if ([currAttrib isEqualToString:CPAttachmentAttributeName])
{
}
else if ([currAttrib isEqualToString:CPLigatureAttributeName])
{
}
else if ([currAttrib isEqualToString:CPKernAttributeName])
{
}
}
substring = substring.replace(/\\/g, '\\\\');
substring = substring.replace(/\n/g, '\\par\n');
substring = substring.replace(/\t/g, '\\tab');
substring = substring.replace(/{/g, '\\{');
substring = substring.replace(/}/g, '\\}');
// FIXME: All characters not in the standard encoding must be
// replaced by \'xx
if (!first)
{
var braces;
if ([headerString length])
braces = [CPString stringWithFormat:@"{%@ %@}", headerString, substring];
else
braces = substring;
result += braces;
}
else
{
var nobraces;
if ([headerString length])
nobraces = [CPString stringWithFormat:@"%@ %@", headerString, substring];
else
nobraces = substring;
result += nobraces;
}
return result + trailerString;
}
- (CPString)bodyString
{
var string = [text string],
result = "",
loc = 0,
length = [string length],
currRange = CPMakeRange(loc, 0),
completeRange = CPMakeRange(0, length),
first = YES;
// FIXME <!> split along newline characters and run as outer loop
while (CPMaxRange(currRange) < CPMaxRange(completeRange)) // save all "runs"
{
var attributes,
substring,
runString;
attributes = [text attributesAtIndex:CPMaxRange(currRange)
longestEffectiveRange:currRange
inRange:completeRange];
substring = [string substringWithRange:currRange];
runString = [self runStringForString:substring
attributes:attributes
paragraphStart:YES];
result += runString;
first = NO;
}
return result;
}
- (CPString)RTFDStringFromAttributedString:(CPAttributedString)aText
documentAttributes:(CPDictionary)dict
{
var output = [CPString string],
headerString,
trailerString,
bodyString;
text = aText;
docDict = dict;
/*
* do not change order! (esp. body has to be generated first; builds context)
*/
bodyString = [self bodyString];
trailerString = [self trailerString];
headerString = [self headerString];
output += headerString;
output += bodyString;
output += trailerString;
return output;
}
@end
+2 -2
View File
@@ -2906,8 +2906,8 @@ setBoundsOrigin:
return YES;
}
/*
FIXME Not yet implemented
/*!
Scrolls the views CPClipView in the direction of a mouse event that occurs outside of it.
*/
- (BOOL)autoscroll:(CPEvent)anEvent
{
+6 -4
View File
@@ -384,9 +384,10 @@ Return true if the event may be a copy and paste event, but the target is not an
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
var pasteboard = [CPPasteboard generalPasteboard],
cappString = [pasteboard stringForType:CPStringPboardType];
if ([pasteboard _stateUID] != value)
if (cappString != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
@@ -450,9 +451,10 @@ Return true if the event may be a copy and paste event, but the target is not an
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
var pasteboard = [CPPasteboard generalPasteboard],
cappString = [pasteboard stringForType:CPStringPboardType];
if ([pasteboard _stateUID] != value)
if (cappString != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
+3 -1
View File
@@ -171,7 +171,9 @@ var DOMFixedWidthSpanElement = nil,
span.style.width = ROUND(aWidth) + "px";
}
span.style.font = [(aFont || DefaultFont) cssString];
var effectiveFontCSSString = [(aFont || DefaultFont) cssString];
if (span.style.font !== effectiveFontCSSString)
span.style.font = effectiveFontCSSString;
if (CPFeatureIsCompatible(CPJavaScriptInnerTextFeature))
span.innerText = aString;
+5 -2
View File
@@ -389,8 +389,11 @@ var themedButtonValues = nil,
var color = [CPColor blackColor],
themedColorValues =
[
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]]
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]],
[@"selected-text-background-color", [CPColor colorWithHexString:"99CCFF"]],
[@"selected-text-inactive-background-color", [CPColor colorWithHexString:"CCCCCC"]]
];
[self registerThemeValues:themedColorValues forObject:color];
+4 -2
View File
@@ -106,8 +106,10 @@ var themedButtonValues = nil,
var color = [CPColor redColor],
themedColorValues =
[
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]]
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]],
[@"selected-text-background-color", [CPColor colorWithHexString:"99CCFF"]],
[@"selected-text-inactive-background-color", [CPColor colorWithHexString:"CCCCCC"]]
];
[self registerThemeValues:themedColorValues forObject:color];
+87
View File
@@ -0,0 +1,87 @@
@import <AppKit/CPTextView.j>
@import <OJMoq/OJMoq.j>
@implementation CPTextViewTest : OJTestCase
{
CPWindow theWindow;
CPTextView textView;
CPString stringValue;
OJMoqSpy delegateSpy
}
- (void)setUp
{
// This will init the global var CPApp which are used internally in the AppKit
[[CPApplication alloc] init];
// setup a reasonable table
theWindow = [[CPWindow alloc] initWithContentRect:CGRectMake(0.0, 0.0, 1024.0, 768.0) styleMask:CPWindowNotSizable];
textView = [[CPTextView alloc] initWithFrame:CGRectMake(0,0,300,300)];
stringValue = @"My string is here";
[textView setString:stringValue];
[textView setDelegate:self];
[[theWindow contentView] addSubview:textView];
delegateSpy = spy(self);
}
- (void)tearDown
{
[delegateSpy reset];
}
- (void)testMakeCPTextViewInstance
{
[self assertNotNull:textView];
}
- (void)testTextViewSetStringMethod
{
[self assert:stringValue equals:[textView stringValue]];
}
- (void)testTextViewSelectionRange
{
//TODO : uncomment once ojtest will be up to date on travis
var range;
//
//[delegateSpy selector:@selector(textView:willChangeSelectionFromCharacterRange:toCharacterRange:) times:1 arguments:[textView, CPMakeRange(0,0), CPMakeRange(0, 18)]];
//[delegateSpy selector:@selector(textViewDidChangeSelection:) times:1];
//[textView selectAll:self];
//range = [[textView selectedRanges] firstObject];
//[self assert:0 equals:range.location];
//[self assert:18 equals:range.length];
// [delegateSpy verifyThatAllExpectationsHaveBeenMet];
//
//
// [delegateSpy reset];
// [delegateSpy selector:@selector(textView:willChangeSelectionFromCharacterRange:toCharacterRange:) times:1 arguments:[textView, CPMakeRange(0, 18), CPMakeRange(3, 6)]];
// [delegateSpy selector:@selector(textViewDidChangeSelection:) times:1];
//[textView setSelectedRange:CPMakeRange(3, 6)];
//range = [[textView selectedRanges] firstObject];
//[self assert:3 equals:range.location];
//[self assert:6 equals:range.length];
// [delegateSpy verifyThatAllExpectationsHaveBeenMet];
}
@end
@implementation CPTextViewTest (CPTextViewTestDelegate)
- (CPRange)textView:(CPTextView)aTextView willChangeSelectionFromCharacterRange:(CPRange)oldSelectedCharRange toCharacterRange:(CPRange)newSelectedCharRange
{
return newSelectedCharRange;
}
- (void)textViewDidChangeSelection:(CPNotification)aNotification
{
}
@end
+105
View File
@@ -0,0 +1,105 @@
/*
* AppController.j
*
* Manual test application for the cappuccino text system
* Copyright (C) 2014 Daniel Boehringer
*/
@import <Foundation/Foundation.j>
@import <AppKit/CPTextView.j>
@import <AppKit/CPFontPanel.j>
@implementation AppController : CPObject
{
CPTextView _textView;
CPTextView _textView2;
}
- (void)orderFrontFontPanel:(id)sender
{
[[CPFontManager sharedFontManager] orderFrontFontPanel:self];
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
// CPLogRegister(CPLogConsole);
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView];
[contentView setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
_textView = [[CPTextView alloc] initWithFrame:CGRectMake(0,0,500,500)];
[_textView setRichText:YES];
_textView2 = [[CPTextView alloc] initWithFrame:CGRectMake(0,0,500,500)];
_textView2._isRichText = NO;
[_textView setBackgroundColor:[CPColor whiteColor]];
[_textView2 setBackgroundColor:[CPColor whiteColor]];
var scrollView = [[CPScrollView alloc] initWithFrame:CGRectMake(20, 20,520,510)];
var scrollView2 = [[CPScrollView alloc] initWithFrame:CGRectMake(560, 20,520,510)];
// [scrollView setAutohidesScrollers:YES];
[scrollView setDocumentView:_textView];
[scrollView2 setDocumentView:_textView2];
//
[contentView addSubview: scrollView];
[contentView addSubview: scrollView2];
//
// [_textView setDelegate:self];
//
// build our menu
var mainMenu = [CPApp mainMenu];
while ([mainMenu numberOfItems] > 0)
[mainMenu removeItemAtIndex:0];
var item = [mainMenu insertItemWithTitle:@"Edit" action:nil keyEquivalent:nil atIndex:0],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit Menu"];
[editMenu addItemWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
[editMenu addItemWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
[editMenu addItemWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
[editMenu addItemWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""];
[editMenu addItemWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
[editMenu addItemWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"];
[editMenu addItemWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
[mainMenu setSubmenu:editMenu forItem:item];
item = [mainMenu insertItemWithTitle:@"Format" action:nil keyEquivalent:nil atIndex:0];
var formatMenu = [[CPMenu alloc] initWithTitle:@"Format Menu"];
[formatMenu addItemWithTitle:@"Font panel" action:@selector(orderFrontFontPanel:) keyEquivalent:@"f"];
[mainMenu setSubmenu:formatMenu forItem:item];
//
// var centeredParagraph=[CPParagraphStyle new];
// [centeredParagraph setAlignment: CPCenterTextAlignment];
// [_textView insertText:[[CPAttributedString alloc] initWithString:@"Fusce\n"
// attributes:[CPDictionary dictionaryWithObjects:[centeredParagraph, [CPFont boldFontWithName:"Arial" size:18], [CPColor redColor]]
// forKeys:[CPParagraphStyleAttributeName, CPFontAttributeName, CPForegroundColorAttributeName]]]];
//
// [_textView insertText: [[CPAttributedString alloc] initWithString:@"lectus neque cr as eget lectus neque cr as eget lectus cr as eget lectus"
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont fontWithName:"Arial" size:12]] forKeys: [CPFontAttributeName]]]];
//
// [_textView insertText:[[CPAttributedString alloc] initWithString:@" proin, this is text in boldface "
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont boldFontWithName:"Arial" size:12]] forKeys: [CPFontAttributeName]]]];
// [_textView insertText:[[CPAttributedString alloc] initWithString:@"111111 neque cr as eget lectus neque cr as eget lectus cr as eget lectus"
// attributes:[CPDictionary dictionaryWithObjects:[ [CPFont fontWithName:"Arial" size:12.0]] forKeys: [CPFontAttributeName]]]];
//
[theWindow orderFront:self];
[CPMenu setMenuBarVisible:YES];
}
//
// - (void) makeRTF:sender
// {
// [_textView2 setString: [_CPRTFProducer produceRTF:[_textView textStorage] documentAttributes: @{}] ];
// var tc = [_CPRTFParser new];
// var mystr=[tc parseRTF:[_textView2 stringValue]];
// [_textView selectAll: self];
// [_textView insertText: mystr];
//
// }
@end
+12
View File
@@ -0,0 +1,12 @@
<?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>CPApplicationDelegateClass</key>
<string>AppController</string>
<key>CPBundleName</key>
<string>CPTextViewTest</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
+94
View File
@@ -0,0 +1,94 @@
/*
* Jakefile
* CPLevelIndicator
*
* Created by Alexander Ljungberg on May 28, 2011.
* Copyright 2011, WireLoad 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 ("CPLevelIndicator", function(task)
{
task.setBuildIntermediatesPath(FILE.join("Build", "CPLevelIndicator.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("CPLevelIndicator");
task.setIdentifier("com.yourcompany.CPLevelIndicator");
task.setVersion("1.0");
task.setAuthor("WireLoad");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("CPLevelIndicator");
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", ["CPLevelIndicator"], 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", "CPLevelIndicator", "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", FILE.join("Build", "Release", "CPLevelIndicator", "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Deployment", "CPLevelIndicator"));
OS.system(["press", "-f", FILE.join("Build", "Release", "CPLevelIndicator"), FILE.join("Build", "Deployment", "CPLevelIndicator")]);
printResults("Deployment")
});
task ("desktop", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Desktop", "CPLevelIndicator"));
require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", "CPLevelIndicator"), FILE.join("Build", "Desktop", "CPLevelIndicator", "CPLevelIndicator.app"));
printResults("Desktop")
});
task ("run-desktop", ["desktop"], function()
{
OS.system([FILE.join("Build", "Desktop", "CPLevelIndicator", "CPLevelIndicator.app", "Contents", "MacOS", "NativeHost"), "-i"]);
});
function printResults(configuration)
{
print("----------------------------");
print(configuration+" app built at path: "+FILE.join("Build", configuration, "CPLevelIndicator"));
print("----------------------------");
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

+103
View File
@@ -0,0 +1,103 @@
<!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
CPLevelIndicator
Created by Alexander Ljungberg on May 28, 2011.
Copyright 2011, WireLoad 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" />
<title>CPLevelIndicator</title>
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
</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 CPLevelIndicator...</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-project.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>
+74
View File
@@ -0,0 +1,74 @@
<html>
<!--
index.html
CPLevelIndicator
Created by Alexander Ljungberg on May 28, 2011.
Copyright 2011, WireLoad 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" />
<title>CPTextView</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 CPLevelIndicator...</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-project.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
* CPLevelIndicator
*
* Created by Alexander Ljungberg on May 28, 2011.
* Copyright 2011, WireLoad All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
@@ -0,0 +1,34 @@
/*
* AppController.j
* CPTextViewCibTest
*
* Created by You on June 4, 2014.
* Copyright 2014, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@implementation AppController : CPObject
{
@outlet CPWindow theWindow;
@outlet CPTextView textView;
}
- (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:YES];
}
@end
+14
View File
@@ -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>CPTextViewCibTest</string>
<key>CPBundleVersion</key>
<string>1.0</string>
<key>CPHumanReadableCopyright</key>
<string>Copyright © 2014, Your Company All rights reserved.</string>
</dict>
</plist>
+184
View File
@@ -0,0 +1,184 @@
/*
* Jakefile
* CPTextViewCibTest
*
* Created by You on June 4, 2014.
* Copyright 2014, Your Company 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"),
projectName = "CPTextViewCibTest";
app (projectName, function(task)
{
ENV["OBJJ_INCLUDE_PATHS"] = "Frameworks";
if (configuration === "Debug")
ENV["OBJJ_INCLUDE_PATHS"] = FILE.join(ENV["OBJJ_INCLUDE_PATHS"], configuration);
task.setBuildIntermediatesPath(FILE.join("Build", "CPTextViewCibTest.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("CPTextViewCibTest");
task.setIdentifier("com.yourcompany.CPTextViewCibTest");
task.setVersion("1.0");
task.setAuthor("Your Company");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("CPTextViewCibTest");
task.setSources(new FileList("**/*.j").exclude(FILE.join("Build", "**")).exclude(FILE.join("Frameworks", "Source", "**")));
task.setResources(new FileList("Resources/**"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
});
task ("default", [projectName], function()
{
printResults(configuration);
});
task ("build", ["default"], function()
{
updateApplicationSize();
});
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", projectName, "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", FILE.join("Build", "Release", projectName, "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Deployment", projectName));
OS.system(["press", "-f", FILE.join("Build", "Release", projectName), FILE.join("Build", "Deployment", projectName)]);
printResults("Deployment")
});
task ("desktop", ["release"], function()
{
FILE.mkdirs(FILE.join("Build", "Desktop", projectName));
require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", projectName), FILE.join("Build", "Desktop", projectName, "CPTextViewCibTest.app"));
printResults("Desktop")
});
task ("run-desktop", ["desktop"], function()
{
OS.system([FILE.join("Build", "Desktop", projectName, "CPTextViewCibTest.app", "Contents", "MacOS", "NativeHost"), "-i"]);
});
function printResults(configuration)
{
print("----------------------------");
print(configuration+" app built at path: "+FILE.join("Build", configuration, projectName));
print("----------------------------");
}
function updateApplicationSize()
{
print("Calculating application file sizes...");
var contents = FILE.read(FILE.join("Build", ENV["CONFIGURATION"], projectName, "Info.plist"), { charset:"UTF-8" }),
format = CFPropertyList.sniffedFormatOfString(contents),
plist = CFPropertyList.propertyListFromString(contents),
totalBytes = {executable:0, data:0, mhtml:0};
// Get the size of all framework executables and sprite data
var frameworksDir = "Frameworks";
if (ENV["CONFIGURATION"] === "Debug")
frameworksDir = FILE.join(frameworksDir, "Debug");
var frameworks = FILE.list(frameworksDir);
frameworks.forEach(function(framework)
{
if (framework !== "Source")
addBundleFileSizes(FILE.join(frameworksDir, framework), totalBytes);
});
// Read in the default theme name, and attempt to get its size
var themeName = plist.valueForKey("CPDefaultTheme") || "Aristo2",
themePath = nil;
if (themeName === "Aristo" || themeName === "Aristo2")
themePath = FILE.join(frameworksDir, "AppKit", "Resources", themeName + ".blend");
else
themePath = FILE.join("Frameworks", "Resources", themeName + ".blend");
if (FILE.isDirectory(themePath))
addBundleFileSizes(themePath, totalBytes);
// Add sizes for the app
addBundleFileSizes(FILE.join("Build", ENV["CONFIGURATION"], projectName), totalBytes);
print("Executables: " + totalBytes.executable + ", sprite data: " + totalBytes.data + ", total: " + (totalBytes.executable + totalBytes.data));
var dict = new CFMutableDictionary();
dict.setValueForKey("executable", totalBytes.executable);
dict.setValueForKey("data", totalBytes.data);
dict.setValueForKey("mhtml", totalBytes.mhtml);
plist.setValueForKey("CPApplicationSize", dict);
FILE.write(FILE.join("Build", ENV["CONFIGURATION"], projectName, "Info.plist"), CFPropertyList.stringFromPropertyList(plist, format), { charset:"UTF-8" });
}
function addBundleFileSizes(bundlePath, totalBytes)
{
var bundleName = FILE.basename(bundlePath),
environment = bundleName === "Foundation" ? "Objj" : "Browser",
bundlePath = FILE.join(bundlePath, environment + ".environment");
if (FILE.isDirectory(bundlePath))
{
var filename = bundleName + ".sj",
filePath = new FILE.Path(FILE.join(bundlePath, filename));
if (filePath.exists())
totalBytes.executable += filePath.size();
filePath = new FILE.Path(FILE.join(bundlePath, "dataURLs.txt"));
if (filePath.exists())
totalBytes.data += filePath.size();
filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLData.txt"));
if (filePath.exists())
totalBytes.mhtml += filePath.size();
filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLPaths.txt"));
if (filePath.exists())
totalBytes.mhtml += filePath.size();
}
}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment version="1050" identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
<connections>
<outlet property="delegate" destination="450" id="451"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" id="372">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="jll-qG-fPP">
<rect key="frame" x="20" y="20" width="448" height="320"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" id="iXp-AZ-pxs">
<rect key="frame" x="1" y="1" width="238" height="133"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView identifier="vfokrt" importsGraphics="NO" findStyle="panel" continuousSpellChecking="YES" allowsUndo="YES" usesRuler="YES" usesFontPanel="YES" verticallyResizable="YES" allowsNonContiguousLayout="YES" quoteSubstitution="YES" dashSubstitution="YES" spellingCorrection="YES" smartInsertDelete="YES" id="lio-7d-ZF1">
<rect key="frame" x="0.0" y="0.0" width="446" height="318"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" red="1" green="0.30493083910000002" blue="0.37424202039999999" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="431" height="318"/>
<size key="maxSize" width="463" height="10000000"/>
<attributedString key="textStorage">
<fragment content="Je suis un CPTextView">
<attributes>
<color key="NSColor" red="1" green="0.30493083910000002" blue="0.37424202039999999" alpha="1" colorSpace="calibratedRGB"/>
<font key="NSFont" size="16" name="Arial-Black"/>
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
</attributedString>
<color key="insertionPointColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="431" height="318"/>
<size key="maxSize" width="463" height="10000000"/>
<connections>
<outlet property="delegate" destination="450" id="TUv-WJ-Fxj"/>
</connections>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="tou-bI-pKK">
<rect key="frame" x="-100" y="-100" width="87" height="18"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="HzS-T1-0kM">
<rect key="frame" x="432" y="1" width="15" height="318"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
</subviews>
</view>
<point key="canvasLocation" x="288" y="319"/>
</window>
<customObject id="450" customClass="AppController">
<connections>
<outlet property="textView" destination="lio-7d-ZF1" id="kEd-6Q-HGK"/>
<outlet property="theWindow" destination="371" id="459"/>
</connections>
</customObject>
</objects>
</document>
@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="en">
<!--
index-debug.html
CPTextViewCibTest
Created by You on June 4, 2014.
Copyright 2014, Your Company All rights reserved.
-->
<head>
<meta charset="utf-8">
<!--[if lte IE 8]>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1">
<![endif]-->
<!--[if gte IE 9]>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<![endif]-->
<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">
<title>CPTextViewCibTest</title>
<!-- Custom javascript goes here -->
<!-- End custom javascript -->
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks"];
var progressBar = null;
OBJJ_PROGRESS_CALLBACK = function(percent, appSize, path)
{
percent = percent * 100;
if (!progressBar)
progressBar = document.getElementById("progress-bar");
if (progressBar)
progressBar.style.width = Math.min(percent, 100) + "%";
}
var loadingHTML =
'<div id="loading">' +
' <div id="loading-text">Loading...</div>' +
' <div id="progress-indicator">' +
' <span id="progress-bar" style="width:0%"></span>' +
' </div>' +
'</div>';
</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);
// Tag view DOM elements with a "data-cappuccino-view" attribute that contains
// the class name of the view that created them. Comment this or set to false to disable.
appkit_tag_dom_elements = true;
</script>
<style type="text/css">
html, body, h1, p {
margin: 0;
padding: 0;
}
/* We need a body wrapper because Cappuccino is unhappy if we change the body element */
#cappuccino-body {
/* Position it absolutely so it will fill the height without content */
position: absolute;
top: 0;
bottom: 0;
width: 100%;
/* Put it at the bottom of the stack so it doesn't interfere with UI */
z-index: -1000;
}
#cappuccino-body .container {
display: table;
margin: 0 auto;
height: 100%;
}
#cappuccino-body .content {
display: table-cell;
height: 100%;
vertical-align: top;
}
#loading {
position: relative;
top: 35%;
}
#loading-text {
height: 1.5em;
color: #555;
font: normal bold 36px/36px Arial, sans-serif;
}
#progress-indicator {
padding: 0px;
height: 16px;
border: 5px solid #555;
border-radius: 18px;
background-color: white;
}
#progress-bar {
position: relative;
top: -1px;
left: -1px;
display: block;
height: 18px;
/* Compensate for moving the bar left 1px to overlap the indicator border */
border-right: 1px solid #555;
background-color: #555;
}
#noscript {
position: relative;
top: 35%;
padding: 1em 1.5em;
border: 5px solid #555;
border-radius: 16px;
background-color: white;
color: #555;
text-align: center;
font: bold 24px Arial, sans-serif;
}
#noscript a {
color: #98c0ff;
text-decoration: none;
}
</style>
</head>
<body>
<div id="cappuccino-body">
<div class="container">
<div class="content">
<script type="text/javascript">
document.write(loadingHTML);
</script>
</div>
</div>
<noscript style="position:absolute; top:0; left:0; width:100%; height:100%">
<div class="container">
<div class="content">
<div id="noscript">
<p style="font-size:120%; margin-bottom:.75em">JavaScript is required for this site.</p>
<p><a href="http://www.enable-javascript.com" target="_blank">Enable JavaScript</a></p>
</div>
</div>
</div>
</noscript>
</div>
</body>
</html>
+161
View File
@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html lang="en">
<!--
index.html
CPTextViewCibTest
Created by You on June 4, 2014.
Copyright 2014, Your Company All rights reserved.
-->
<head>
<meta charset="utf-8">
<!--[if lte IE 8]>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7, chrome=1">
<![endif]-->
<!--[if gte IE 9]>
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<![endif]-->
<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">
<title>CPTextViewCibTest</title>
<!-- Custom javascript goes here -->
<!-- End custom javascript -->
<script type="text/javascript">
OBJJ_MAIN_FILE = "main.j";
var progressBar = null;
OBJJ_PROGRESS_CALLBACK = function(percent, appSize, path)
{
percent = percent * 100;
if (!progressBar)
progressBar = document.getElementById("progress-bar");
if (progressBar)
progressBar.style.width = Math.min(percent, 100) + "%";
}
var loadingHTML =
'<div id="loading">' +
' <div id="loading-text">Loading...</div>' +
' <div id="progress-indicator">' +
' <span id="progress-bar" style="width:0%"></span>' +
' </div>' +
'</div>';
</script>
<script type="text/javascript" src="Frameworks/Objective-J/Objective-J.js" charset="UTF-8"></script>
<style type="text/css">
html, body, h1, p {
margin: 0;
padding: 0;
}
/* We need a body wrapper because Cappuccino is unhappy if we change the body element */
#cappuccino-body {
/* Position it absolutely so it will fill the height without content */
position: absolute;
top: 0;
bottom: 0;
width: 100%;
/* Put it at the bottom of the stack so it doesn't interfere with UI */
z-index: -1000;
}
#cappuccino-body .container {
display: table;
margin: 0 auto;
height: 100%;
}
#cappuccino-body .content {
display: table-cell;
height: 100%;
vertical-align: top;
}
#loading {
position: relative;
top: 35%;
}
#loading-text {
height: 1.5em;
color: #555;
font: normal bold 36px/36px Arial, sans-serif;
}
#progress-indicator {
padding: 0px;
height: 16px;
border: 5px solid #555;
border-radius: 18px;
background-color: white;
}
#progress-bar {
position: relative;
top: -1px;
left: -1px;
display: block;
height: 18px;
/* Compensate for moving the bar left 1px to overlap the indicator border */
border-right: 1px solid #555;
background-color: #555;
}
#noscript {
position: relative;
top: 35%;
padding: 1em 1.5em;
border: 5px solid #555;
border-radius: 16px;
background-color: white;
color: #555;
text-align: center;
font: bold 24px Arial, sans-serif;
}
#noscript a {
color: #98c0ff;
text-decoration: none;
}
</style>
</head>
<body>
<div id="cappuccino-body">
<div class="container">
<div class="content">
<script type="text/javascript">
document.write(loadingHTML);
</script>
</div>
</div>
<noscript style="position:absolute; top:0; left:0; width:100%; height:100%">
<div class="container">
<div class="content">
<div id="noscript">
<p style="font-size:120%; margin-bottom:.75em">JavaScript is required for this site.</p>
<p><a href="http://www.enable-javascript.com" target="_blank">Enable JavaScript</a></p>
</div>
</div>
</div>
</noscript>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* CPTextViewCibTest
*
* Created by You on June 4, 2014.
* Copyright 2014, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+7 -1
View File
@@ -45,6 +45,7 @@
@import "NSImage.j"
@import "NSImageView.j"
@import "NSLayoutConstraint.j"
@import "NSLayoutManager.j"
@import "NSLevelIndicator.j"
@import "NSLocalizableString.j"
@import "NSMatrix.j"
@@ -54,6 +55,7 @@
@import "NSNibConnector.j"
@import "NSObjectController.j"
@import "NSOutlineView.j"
@import "NSParagraphStyle.j"
@import "NSPopUpButton.j"
@import "NSPredicateEditor.j"
@import "NSResponder.j"
@@ -73,7 +75,12 @@
@import "NSTableView.j"
@import "NSTabView.j"
@import "NSTabViewItem.j"
@import "NSText.j"
@import "NSTextContainer.j"
@import "NSTextField.j"
@import "NSTextStorage.j"
@import "NSTextView.j"
@import "NSTextViewSharedData.j"
@import "NSTokenField.j"
@import "NSToolbar.j"
@import "NSToolbarFlexibleSpaceItem.j"
@@ -92,7 +99,6 @@
@import "NSAppearance.j"
@import "NSVisualEffectView.j"
function CP_NSMapClassName(aClassName)
{
if (aClassName.indexOf("NS") === 0)
+2
View File
@@ -40,5 +40,7 @@
@implementation NSMutableAttributedString : NSAttributedString
{
}
@end
+63
View File
@@ -0,0 +1,63 @@
/*
* NSText.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPLayoutManager.j>
@class Nib2Cib
@implementation CPLayoutManager (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
self = [super init];
_textStorage = [aCoder decodeObjectForKey:@"NSTextStorage"];
[_textStorage addLayoutManager:self];
return self;
}
@end
@implementation NSLayoutManager : CPLayoutManager
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPLayoutManager class];
}
@end
+66
View File
@@ -0,0 +1,66 @@
/*
* NSParagraphStyle.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPParagraphStyle.j>
@class Nib2Cib
@implementation CPParagraphStyle (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
self = [super init];
return self;
}
@end
@implementation NSParagraphStyle : CPParagraphStyle
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
_alignment = [aCoder decodeIntForKey:@"NSAlignment"];
_firstLineHeadIndent = [aCoder decodeIntForKey:@"NSFirstLineHeadIndent"];
_headIndent = [aCoder decodeIntForKey:@"NSHeadIndent"];
_lineSpacing = [aCoder decodeIntForKey:@"NSLineSpacing"];
_maximumLineHeight = [aCoder decodeIntForKey:@"NSMaxLineHeight"];
_minimumLineHeight = [aCoder decodeIntForKey:@"NSMinLineHeight"];
_paragraphSpacing = [aCoder decodeIntForKey:@"NSParagraphSpacing"];
_tailIndent = [aCoder decodeIntForKey:@"NSTailIndent"];
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPParagraphStyle class];
}
@end
+61
View File
@@ -0,0 +1,61 @@
/*
* NSText.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPText.j>
@class Nib2Cib
@implementation CPText (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
if (self = [super NS_initWithCoder:aCoder])
{
}
return self;
}
@end
@implementation NSText : CPText
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPText class];
}
@end
+64
View File
@@ -0,0 +1,64 @@
/*
* NSTextContainer.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPTextContainer.j>
@class Nib2Cib
@implementation CPTextContainer (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
self = [super init];
_size = CGSizeMake([aCoder decodeIntForKey:@"NSWidth"], 1e7);
_layoutManager = [aCoder decodeObjectForKey:@"NSLayoutManager"];
[_layoutManager addTextContainer:self];
return self;
}
@end
@implementation NSTextContainer : CPTextContainer
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPTextContainer class];
}
@end
+74
View File
@@ -0,0 +1,74 @@
/*
* NSTextStorage.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPTextStorage.j>
@class Nib2Cib
@global CPForegroundColorAttributeName
@implementation CPTextStorage (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
var xibAttributes = [aCoder decodeObjectForKey:@"NSAttributes"],
cibAttributes = @{};
if ([xibAttributes containsKey:@"NSColor"])
[cibAttributes setObject:[xibAttributes valueForKey:@"NSColor"] forKey:CPForegroundColorAttributeName];
if ([xibAttributes containsKey:@"NSFont"])
[cibAttributes setObject:[xibAttributes valueForKey:@"NSFont"] forKey:CPFontAttributeName];
if ([xibAttributes containsKey:@"NSParagraphStyle"])
[cibAttributes setObject:[xibAttributes valueForKey:@"NSParagraphStyle"] forKey:CPParagraphStyleAttributeName];
self = [super initWithString:[aCoder decodeObjectForKey:@"NSString"] attributes:cibAttributes];
return self;
}
@end
@implementation NSTextStorage : CPTextStorage
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPTextStorage class];
}
@end
+74
View File
@@ -0,0 +1,74 @@
/*
* NSTextView.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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 <AppKit/CPTextView.j>
@import "NSTextViewSharedData.j"
@class Nib2Cib
@implementation CPTextView (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder textViewSharedData:(CPTextViewSharedData)aTextViewSharedData
{
if (self = [super NS_initWithCoder:aCoder])
{
_textContainer = [aCoder decodeObjectForKey:@"NSTextContainer"];
[self setEditable:[aTextViewSharedData isEditable]];
[self setSelectable:[aTextViewSharedData isSelectable]];
[self setRichText:[aTextViewSharedData isRichText]];
[self setAllowsUndo:[aTextViewSharedData allowsUndo]];
[self setUsesFontPanel:[aTextViewSharedData usesFontPanel]];
[self setBackgroundColor:[aTextViewSharedData backgroundColor]];
[self setInsertionPointColor:[aTextViewSharedData insertionColor]];
[self setSelectedTextAttributes:[aTextViewSharedData selectedTextAttributes]];
[[self textContainer] setWidthTracksTextView:YES];
}
return self;
}
@end
@implementation NSTextView : CPTextView
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [self NS_initWithCoder:aCoder textViewSharedData:[aCoder decodeObjectForKey:@"NSSharedData"]])
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPTextView class];
}
@end
+100
View File
@@ -0,0 +1,100 @@
/*
* NSTextView.j
* nib2cib
*
* Created by Alexendre Wilhelm.
* Copyright 2014 The Cappuccino Foundation.
*
* 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/Foundation.j>
@import <AppKit/CPColor.j>
@import <AppKit/CPParagraphStyle.j>
@class Nib2Cib
@implementation CPTextViewSharedData : CPObject
{
BOOL _allowsUndo @accessors(getter=allowsUndo);
BOOL _editable @accessors(getter=isEditable);
BOOL _richText @accessors(getter=isRichText);
BOOL _selectable @accessors(getter=isSelectable);
BOOL _usesFontPanel @accessors(getter=usesFontPanel);
CPColor _backgroundColor @accessors(getter=backgroundColor);
CPColor _insertionColor @accessors(getter=insertionColor);
CPDictionary _selectedTextAttributes @accessors(getter=selectedTextAttributes);
}
- (id)init
{
if (self = [super init])
{
}
return self;
}
@end
@implementation CPTextViewSharedData (NSCoding)
- (id)NS_initWithCoder:(CPCoder)aCoder
{
if (self = [super init])
{
var flags = [aCoder decodeIntForKey:@"NSFlags"];
_allowsUndo = (flags & 0x0000400) ? YES : NO;
_editable = (flags & 0x00000002) ? YES : NO;
_richText = (flags & 0x00000004) ? YES : NO;
_selectable = (flags & 0x00000001) ? YES : NO;
_usesFontPanel = (flags & 0x00000020) ? YES : NO;
_backgroundColor = [aCoder decodeObjectForKey:@"NSBackgroundColor"];
_insertionColor = [aCoder decodeObjectForKey:@"NSInsertionColor"];
_selectedTextAttributes = [aCoder decodeObjectForKey:@"NSSelectedAttributes"];
}
return self;
}
@end
@implementation NSTextViewSharedData : CPTextViewSharedData
{
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [self NS_initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (Class)classForKeyedArchiver
{
return [CPTextViewSharedData class];
}
@end