Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a80147bafd | ||
|
|
f170e4812d | ||
|
|
070728aea9 | ||
|
|
5e3ae58d42 | ||
|
|
b4e4bdb924 | ||
|
|
0f097e0ff4 | ||
|
|
e38845f993 | ||
|
|
f4f4dd8025 | ||
|
|
c942259c90 | ||
|
|
a4fb0920f6 | ||
|
|
4d47b5abf5 |
@@ -9,4 +9,3 @@ WebSite
|
||||
*.xcodeproj/*.perspectivev3
|
||||
xcuserdata/
|
||||
!*.xcodeproj/project.pbxproj
|
||||
target
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
@import "CPAnimation.j"
|
||||
@import "CPApplication.j"
|
||||
@import "CPArrayController.j"
|
||||
@import "CPAttributedString+Additions.j"
|
||||
@import "CPBezierPath.j"
|
||||
@import "CPBox.j"
|
||||
@import "CPBrowser.j"
|
||||
@@ -37,14 +38,12 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorWell.j"
|
||||
@import "CPComboBox.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPControl.j"
|
||||
@import "CPCookie.j"
|
||||
@@ -68,7 +67,6 @@
|
||||
@import "CPOutlineView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPPopover.j"
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPPredicateEditor.j"
|
||||
@import "CPPredicateEditorRowTemplate.j"
|
||||
@@ -86,6 +84,7 @@
|
||||
@import "CPSound.j"
|
||||
@import "CPSplitView.j"
|
||||
@import "CPStepper.j"
|
||||
@import "CPString+Additions.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTabView.j"
|
||||
|
||||
@@ -117,7 +117,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
|
||||
{
|
||||
var alert = [[self alloc] init];
|
||||
var alert = [[CPAlert alloc] init];
|
||||
|
||||
[alert setMessageText:aMessage];
|
||||
[alert addButtonWithTitle:defaultButtonTitle];
|
||||
@@ -142,7 +142,7 @@ CPCriticalAlertStyle = 2;
|
||||
*/
|
||||
+ (CPAlert)alertWithError:(CPString)anErrorMessage
|
||||
{
|
||||
var alert = [[self alloc] init];
|
||||
var alert = [[CPAlert alloc] init];
|
||||
|
||||
[alert setMessageText:anErrorMessage];
|
||||
[alert setAlertStyle:CPCriticalAlertStyle];
|
||||
|
||||
@@ -306,9 +306,6 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
if (_animationCurve == CPAnimationLinear)
|
||||
return t;
|
||||
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
@@ -107,7 +107,7 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPArray _themeBlends @accessors(property=themeBlends);
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -141,8 +141,6 @@ CPRunContinuesResponse = -1002;
|
||||
_windows = [];
|
||||
|
||||
[_windows addObject:nil];
|
||||
|
||||
_themeBlends = [];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -340,7 +338,7 @@ CPRunContinuesResponse = -1002;
|
||||
Copyright - Human readable copyright information.
|
||||
</pre>
|
||||
|
||||
If you choose not the include any of the above keys, they will default
|
||||
If you choose not the include any of the above keys, they will default
|
||||
to the following respective keys in your info.plist file.
|
||||
|
||||
<pre>
|
||||
@@ -1005,7 +1003,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the arguments of your application.
|
||||
Sets the arguments of your application.
|
||||
That is, set the slash seperated values of an array as the window location hash.
|
||||
|
||||
For example if you pass an array:
|
||||
@@ -1158,16 +1156,6 @@ CPRunContinuesResponse = -1002;
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (CPThemeBlend)themeBlend
|
||||
{
|
||||
return (_themeBlends.length > 0 ? _themeBlends[0] : nil);
|
||||
}
|
||||
|
||||
- (void)setThemeBlend:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
_themeBlends[0] = aThemeBlend;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
@@ -1230,14 +1218,15 @@ function CPApplicationMain(args, namedArgs)
|
||||
[_CPAppBootstrapper performActions];
|
||||
}
|
||||
|
||||
var _CPAppBootstrapperActions = nil,
|
||||
_CPAppThemeURLsToLoad = [];
|
||||
var _CPAppBootstrapperActions = nil;
|
||||
|
||||
@implementation _CPAppBootstrapper : CPObject
|
||||
{
|
||||
}
|
||||
|
||||
+ (CPArray)actions
|
||||
{
|
||||
return [@selector(bootstrapPlatform), @selector(loadThemes), @selector(loadMainCibFile)];
|
||||
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
|
||||
}
|
||||
|
||||
+ (void)performActions
|
||||
@@ -1261,30 +1250,17 @@ var _CPAppBootstrapperActions = nil,
|
||||
return [CPPlatform bootstrap];
|
||||
}
|
||||
|
||||
+ (BOOL)loadThemes
|
||||
+ (BOOL)loadDefaultTheme
|
||||
{
|
||||
_CPAppThemeURLsToLoad.push([CPApplication defaultThemeName]);
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
|
||||
var auxiliaryThemes = ([[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPAuxiliaryThemes"] || []);
|
||||
|
||||
_CPAppThemeURLsToLoad = _CPAppThemeURLsToLoad.concat(auxiliaryThemes);
|
||||
|
||||
[self loadNextTheme];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (BOOL)loadNextTheme
|
||||
{
|
||||
var themeName = _CPAppThemeURLsToLoad.shift();
|
||||
|
||||
if (themeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:themeName + @".blend"];
|
||||
if (defaultThemeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:themeName + @".blend"];
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1292,17 +1268,10 @@ var _CPAppBootstrapperActions = nil,
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
var themeBlends = [CPApp themeBlends];
|
||||
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
[themeBlends addObject:aThemeBlend];
|
||||
|
||||
if ([themeBlends count] === 1)
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
if (_CPAppThemeURLsToLoad.length === 0)
|
||||
[self performActions];
|
||||
else
|
||||
[self loadNextTheme];
|
||||
[self performActions];
|
||||
}
|
||||
|
||||
+ (BOOL)loadMainCibFile
|
||||
|
||||
@@ -564,9 +564,8 @@
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
[self _selectionWillChange]
|
||||
var r = [self __setSelectionIndexes:indexes];
|
||||
[self __setSelectionIndexes:indexes];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -575,7 +574,7 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||
{
|
||||
return [self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -584,38 +583,28 @@
|
||||
*/
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
var newIndexes = indexes;
|
||||
if (!indexes)
|
||||
indexes = [CPIndexSet indexSet];
|
||||
|
||||
if (!newIndexes)
|
||||
newIndexes = [CPIndexSet indexSet];
|
||||
|
||||
if (![newIndexes count])
|
||||
if (![indexes count])
|
||||
{
|
||||
if (_avoidsEmptySelection && [[self arrangedObjects] count])
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:0];
|
||||
indexes = [CPIndexSet indexSetWithIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var objectsCount = [[self arrangedObjects] count];
|
||||
|
||||
// Don't trash the input - the caller might depend on it or we might have been
|
||||
// given _selectionIndexes as the input in which case the equality test below
|
||||
// would always succeed despite our change below.
|
||||
newIndexes = [newIndexes copy];
|
||||
|
||||
// Remove out of bounds indexes.
|
||||
[newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
|
||||
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
|
||||
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
|
||||
if (![newIndexes count] && _avoidsEmptySelection && objectsCount)
|
||||
newIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
if (![indexes count] && _avoidsEmptySelection && objectsCount)
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
if ([_selectionIndexes isEqualToIndexSet:newIndexes])
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
return NO;
|
||||
|
||||
// If we haven't already created our own index instance, make sure to copy it here so that
|
||||
// the copy the user sent in is decoupled from our internal copy.
|
||||
_selectionIndexes = indexes === newIndexes ? [indexes copy] : newIndexes;
|
||||
_selectionIndexes = [indexes copy];
|
||||
|
||||
// Push back the new selection to the model for selectionIndexes if we have one.
|
||||
// There won't be an infinite loop because of the equality check above.
|
||||
@@ -647,11 +636,10 @@
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
|
||||
var r = [self __setSelectedObjects:objects];
|
||||
[self __setSelectedObjects:objects];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionDidChange];
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* CPAttributedString+Additions.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Randy Luecke
|
||||
* Copyright 2011, RCLConcepts, LLC.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
AppKit adds two methods to the CPAttributedString class to support drawing string directly in an CPView.
|
||||
|
||||
AppKit also adds similar methods to CPString.
|
||||
*/
|
||||
@implementation CPAttributedString (AppKitAdditions)
|
||||
/*!
|
||||
Draws a string in the current graphics context.
|
||||
This method and draws the reciver on a single "infinately long" line.
|
||||
|
||||
@param aPoint - The starting point to draw the string
|
||||
*/
|
||||
- (void)drawAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
line = CTLineCreateWithAttributedString([self copy]);
|
||||
|
||||
CGContextSetTextPosition(context, aPoint.x, aPoint.y);
|
||||
CTLineDraw(line, context);
|
||||
}
|
||||
|
||||
/*!
|
||||
Draws a string in the current graphics context.
|
||||
|
||||
@param aRect - The rect for which the string should be drawn into
|
||||
*/
|
||||
- (void)drawInRect:(CGRect)aRect
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
frameSetter = CTFramesetterCreateWithAttributedString([self copy]),
|
||||
path = CGPathCreateMutable();
|
||||
|
||||
CGPathAddRect(path, nil, aRect);
|
||||
|
||||
var frame = CTFramesetterCreateFrame(frameSetter, CPMakeRange(0, [self length]), path, nil);
|
||||
|
||||
CTFrameDraw(frame, context);
|
||||
}
|
||||
@end
|
||||
@@ -61,7 +61,6 @@ CPGrooveBorder = 3;
|
||||
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[box setAutoresizingMask:[aView autoresizingMask]];
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
@import "CPCompatibility.j"
|
||||
@import "CPImage.j"
|
||||
|
||||
/// @cond IGNORE
|
||||
|
||||
var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
@@ -55,66 +54,6 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/// @endcond
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for vertical patterns.
|
||||
*/
|
||||
CPColorPatternIsVertical = YES,
|
||||
|
||||
/*!
|
||||
Orientation to use with \c CPColorPattern for horizontal patterns.
|
||||
*/
|
||||
CPColorPatternIsHorizontal = NO;
|
||||
|
||||
/*!
|
||||
To create a simple color with a pattern image:
|
||||
|
||||
<code>CPColorWithImages(name, width, height{, bundle})</code>
|
||||
|
||||
To create a color with a three part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices{, orientation})</code>
|
||||
|
||||
where slices is an array of three [name, width, height{, bundle}] arrays,
|
||||
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
|
||||
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
|
||||
|
||||
To create a color with a nine part pattern image:
|
||||
|
||||
<code>CPColorWithImages(slices);</code>
|
||||
|
||||
where slices is an array of nine [name, width, height{, bundle}] arrays.
|
||||
*/
|
||||
function CPColorWithImages()
|
||||
{
|
||||
if (arguments.length < 3)
|
||||
{
|
||||
var slices = arguments[0],
|
||||
imageSlices = [];
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var slice = slices[i];
|
||||
|
||||
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
|
||||
}
|
||||
|
||||
if (imageSlices.length === 3)
|
||||
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
|
||||
else
|
||||
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
|
||||
}
|
||||
else if (arguments.length === 3 || arguments.length === 4)
|
||||
{
|
||||
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
@@ -694,36 +633,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var description = [super description],
|
||||
patternImage = [self patternImage];
|
||||
|
||||
if (!patternImage)
|
||||
return description + " " + [self cssString];
|
||||
|
||||
description += " {\n";
|
||||
|
||||
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
|
||||
{
|
||||
var slices = [patternImage imageSlices];
|
||||
|
||||
if ([patternImage isThreePartImage])
|
||||
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
|
||||
|
||||
description += " patternImage (" + slices.length + " part): [\n";
|
||||
|
||||
for (var i = 0; i < slices.length; ++i)
|
||||
{
|
||||
var imgDescription = [slices[i] description];
|
||||
|
||||
description += imgDescription.replace(/^/mg, " ") + ",\n";
|
||||
}
|
||||
|
||||
description = description.substr(0, description.length - 2) + "\n ]\n}";
|
||||
}
|
||||
else
|
||||
description += [patternImage description].replace(/^/mg, " ") + "\n}";
|
||||
|
||||
return description;
|
||||
return [super description]+" "+[self cssString];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -768,10 +678,8 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
@end
|
||||
|
||||
/// @cond IGNORE
|
||||
var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
CPColorPatternImageKey = @"CPColorPatternImageKey";
|
||||
/// @endcond
|
||||
|
||||
@implementation CPColor (CPCoding)
|
||||
|
||||
@@ -802,12 +710,13 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
@end
|
||||
|
||||
|
||||
/// @cond IGNORE
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*
|
||||
Used for the CPColor +colorWithHexString: implementation.
|
||||
Returns an array of rgb components.
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@ignore
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
*/
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
@@ -845,5 +754,3 @@ var byteToHex = function(n)
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
/// @endcond
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "../Foundation/CPFormatter.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@@ -85,7 +82,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
CPFormatter _formatter @accessors(property=formatter);
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
@@ -225,11 +221,10 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@param anAction the action to send
|
||||
@param anObject the object to which the action will be sent
|
||||
*/
|
||||
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
|
||||
return [CPApp sendAction:anAction to:anObject from:self];
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
- (int)sendActionOn:(int)mask
|
||||
@@ -507,46 +502,15 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
if (_formatter && _value !== undefined && _value !== nil)
|
||||
{
|
||||
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
|
||||
|
||||
if (formattedValue !== nil && formattedValue !== undefined)
|
||||
return formattedValue;
|
||||
}
|
||||
|
||||
return (_value === undefined || _value === nil) ? "" : String(_value);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's string value.
|
||||
*/
|
||||
- (void)setStringValue:(CPString)aString
|
||||
- (void)setStringValue:(CPString)anObject
|
||||
{
|
||||
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
|
||||
if (aString === nil || aString === undefined)
|
||||
{
|
||||
CPLog.warn("nil or undefined sent to CPControl -setStringValue");
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
if (_formatter)
|
||||
{
|
||||
value = nil;
|
||||
|
||||
if (![_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil])
|
||||
{
|
||||
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
|
||||
if (!aString || ![_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil])
|
||||
value = undefined; // Means the value is invalid
|
||||
}
|
||||
}
|
||||
else
|
||||
value = aString;
|
||||
|
||||
[self setObjectValue:value];
|
||||
[self setObjectValue:anObject];
|
||||
}
|
||||
|
||||
- (void)takeDoubleValueFrom:(id)sender
|
||||
@@ -562,18 +526,21 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setFloatValue:[sender floatValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntegerValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(integerValue)])
|
||||
[self setIntegerValue:[sender integerValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeIntValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(intValue)])
|
||||
[self setIntValue:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)takeObjectValueFrom:(id)sender
|
||||
{
|
||||
if ([sender respondsToSelector:@selector(objectValue)])
|
||||
@@ -915,7 +882,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
if (_target !== nil)
|
||||
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
|
||||
|
||||
if (_action !== nil)
|
||||
if (_action !== NULL)
|
||||
[aCoder encodeObject:_action forKey:CPControlActionKey];
|
||||
|
||||
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
|
||||
|
||||
@@ -571,28 +571,29 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
// Cocoa does not consider space, backspace, or escape a key equivalent
|
||||
// if the first responder is a text field (presumably a subclass of NSText).
|
||||
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
|
||||
|
||||
for (var i = 0; i < characterCount; i++)
|
||||
{
|
||||
var c = _characters.charAt(i);
|
||||
|
||||
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
|
||||
c === CPEnterCharacter ||
|
||||
c === CPNewlineCharacter ||
|
||||
c === CPCarriageReturnCharacter ||
|
||||
c === CPEscapeFunctionKey ||
|
||||
(!firstResponderIsText &&
|
||||
(c === CPSpaceFunctionKey ||
|
||||
c === CPDeleteCharacter ||
|
||||
c === CPBackspaceCharacter)))
|
||||
switch (_characters.charAt(i))
|
||||
{
|
||||
return YES;
|
||||
case CPBackspaceCharacter:
|
||||
case CPDeleteCharacter:
|
||||
case CPDeleteFunctionKey:
|
||||
case CPTabCharacter:
|
||||
case CPCarriageReturnCharacter:
|
||||
case CPNewlineCharacter:
|
||||
case CPSpaceFunctionKey:
|
||||
case CPEscapeFunctionKey:
|
||||
case CPPageUpFunctionKey:
|
||||
case CPPageDownFunctionKey:
|
||||
case CPLeftArrowFunctionKey:
|
||||
case CPUpArrowFunctionKey:
|
||||
case CPRightArrowFunctionKey:
|
||||
case CPDownArrowFunctionKey:
|
||||
case CPEndFunctionKey:
|
||||
case CPHomeFunctionKey:
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: More cases?
|
||||
return NO;
|
||||
}
|
||||
@@ -650,3 +651,4 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
|
||||
|
||||
return aNativeEvent;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,7 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
|
||||
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
|
||||
|
||||
var imagesForNames = { },
|
||||
AppKitImageForNames = { },
|
||||
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
|
||||
AppKitImageForNames = { };
|
||||
|
||||
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
|
||||
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
|
||||
@@ -325,24 +324,6 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var filename = [self filename],
|
||||
size = [self size];
|
||||
|
||||
if (filename.indexOf("data:") === 0)
|
||||
{
|
||||
var index = filename.indexOf(",");
|
||||
|
||||
if (index > 0)
|
||||
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
|
||||
else
|
||||
filename = "data:<unknown type>";
|
||||
}
|
||||
|
||||
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_derefFromImage
|
||||
{
|
||||
|
||||
@@ -204,6 +204,7 @@ var CPBindingOperationAnd = 0,
|
||||
if (valueTransformer)
|
||||
aValue = [valueTransformer transformedValue:aValue];
|
||||
|
||||
|
||||
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
|
||||
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
|
||||
|
||||
@@ -310,7 +311,7 @@ var CPBindingOperationAnd = 0,
|
||||
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
|
||||
{
|
||||
if (!anObject || !aKeyPath)
|
||||
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
|
||||
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
|
||||
|
||||
//if (![[self exposedBindings] containsObject:aBinding])
|
||||
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
|
||||
@@ -487,8 +488,6 @@ CPSelectedIndexBinding = @"selectedIndex";
|
||||
CPTextColorBinding = @"textColor";
|
||||
CPToolTipBinding = @"toolTip";
|
||||
CPValueBinding = @"value";
|
||||
CPContentBinding = @"content";
|
||||
CPContentValuesBinding = @"contentValues";
|
||||
|
||||
//Binding options constants
|
||||
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
|
||||
@@ -519,4 +518,4 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
|
||||
CPIsControllerMarker = function(/*id*/anObject)
|
||||
{
|
||||
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
|
||||
}
|
||||
}
|
||||
@@ -149,9 +149,9 @@ var _CPLevelIndicatorBezelColor = nil,
|
||||
var filledColor = _CPLevelIndicatorSegmentNormalColor,
|
||||
value = [self doubleValue];
|
||||
|
||||
if (value <= _criticalValue)
|
||||
if (value < _criticalValue)
|
||||
filledColor = _CPLevelIndicatorSegmentCriticalColor;
|
||||
else if (value <= _warningValue)
|
||||
else if (value < _warningValue)
|
||||
filledColor = _CPLevelIndicatorSegmentWarningColor;
|
||||
|
||||
for (var i = 0; i < segmentCount; i++)
|
||||
|
||||
@@ -622,11 +622,11 @@ var _CPMenuBarVisible = NO,
|
||||
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
|
||||
|
||||
if (!validator || ![validator respondsToSelector:[item action]])
|
||||
[item setEnabled:NO];
|
||||
[item _setEnabled:NO];
|
||||
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
|
||||
[item setEnabled:[validator validateMenuItem:item]];
|
||||
[item _setEnabled:[validator validateMenuItem:item]];
|
||||
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
|
||||
[item setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
[item _setEnabled:[validator validateUserInterfaceItem:item]];
|
||||
}
|
||||
|
||||
[[_menuWindow _menuView] tile];
|
||||
@@ -711,7 +711,10 @@ var _CPMenuBarVisible = NO,
|
||||
if (aView && !theWindow)
|
||||
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
|
||||
|
||||
[self _menuWillOpen];
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
|
||||
// Convert location to global coordinates if not already in them.
|
||||
if (aView)
|
||||
@@ -799,7 +802,10 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||
{
|
||||
[aMenu _menuWillOpen];
|
||||
var delegate = [aMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:aMenu];
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
@@ -869,15 +875,7 @@ var _CPMenuBarVisible = NO,
|
||||
*/
|
||||
- (CPMenuItem)highlightedItem
|
||||
{
|
||||
if (_highlightedIndex < 0)
|
||||
return nil;
|
||||
|
||||
var highlightedItem = _items[_highlightedIndex];
|
||||
|
||||
if ([highlightedItem isSeparatorItem])
|
||||
return nil;
|
||||
|
||||
return highlightedItem;
|
||||
return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
|
||||
}
|
||||
|
||||
// Managing the Delegate
|
||||
@@ -892,22 +890,6 @@ var _CPMenuBarVisible = NO,
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)_menuWillOpen
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:self];
|
||||
}
|
||||
|
||||
- (void)_menuDidClose
|
||||
{
|
||||
var delegate = [self delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:self];
|
||||
}
|
||||
|
||||
// Handling Tracking
|
||||
/*!
|
||||
Cancels tracking.
|
||||
|
||||
@@ -11,7 +11,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
@implementation _CPMenuManager: CPObject
|
||||
{
|
||||
CPTimeInterval _startTime;
|
||||
BOOL _hasMouseGoneUpAfterStartedTracking;
|
||||
int _scrollingState;
|
||||
CGPoint _lastGlobalLocation;
|
||||
|
||||
@@ -61,9 +60,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
{
|
||||
var menu = [aMenuContainer menu];
|
||||
|
||||
if ([menu numberOfItems] <= 0)
|
||||
return;
|
||||
|
||||
CPApp._activeMenu = menu;
|
||||
|
||||
_startTime = [anEvent timestamp];//new Date();
|
||||
@@ -91,8 +87,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
return [self trackMenuBarButtonEvent:anEvent];
|
||||
}
|
||||
|
||||
_hasMouseGoneUpAfterStartedTracking = NO;
|
||||
|
||||
[self trackEvent:anEvent];
|
||||
}
|
||||
|
||||
@@ -105,7 +99,7 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPKeyDown)
|
||||
{
|
||||
@@ -227,20 +221,8 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseUp || type === CPRightMouseUp)
|
||||
{
|
||||
if (_hasMouseGoneUpAfterStartedTracking)
|
||||
{
|
||||
// Don't close the menu if the current item has a submenu
|
||||
// and did not override it's default action
|
||||
if ([activeItem action] === @selector(submenuAction:))
|
||||
return;
|
||||
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
else
|
||||
_hasMouseGoneUpAfterStartedTracking = YES;
|
||||
}
|
||||
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
|
||||
[trackingMenu cancelTracking];
|
||||
}
|
||||
|
||||
// Prevent previous selected menu items from opening by stopping the timer if a
|
||||
@@ -324,7 +306,11 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
// Hide all submenus.
|
||||
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
|
||||
[trackingMenu _menuDidClose];
|
||||
|
||||
var delegate = [trackingMenu delegate];
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuDidClose:)])
|
||||
[delegate menuDidClose:trackingMenu];
|
||||
|
||||
if (_trackingCallback)
|
||||
_trackingCallback([self trackingMenuContainer], trackingMenu);
|
||||
@@ -393,8 +379,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
var count = _menuContainerStack.length,
|
||||
index = count;
|
||||
|
||||
[newMenu _menuWillOpen];
|
||||
|
||||
// Hide all menus up to the base menu...
|
||||
while (index--)
|
||||
{
|
||||
@@ -414,8 +398,6 @@ var STICKY_TIME_INTERVAL = 500,
|
||||
|
||||
[_CPMenuWindow poolMenuWindow:menuContainer];
|
||||
[_menuContainerStack removeObjectAtIndex:index];
|
||||
|
||||
[menu _menuDidClose];
|
||||
}
|
||||
|
||||
if (!newMenu)
|
||||
|
||||
@@ -148,6 +148,14 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
|
||||
@param isEnabled \c YES enables the item. \c NO disables it.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if ([_menu autoenablesItems])
|
||||
return;
|
||||
|
||||
[self _setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
- (void)_setEnabled:(BOOL)isEnabled
|
||||
{
|
||||
if (_isEnabled === isEnabled)
|
||||
return;
|
||||
@@ -488,7 +496,6 @@ CPOffState
|
||||
if (_submenu)
|
||||
{
|
||||
[_submenu setSupermenu:_menu];
|
||||
[_submenu setTitle:[self title]]
|
||||
|
||||
[self setTarget:_menu];
|
||||
[self setAction:@selector(submenuAction:)];
|
||||
|
||||
@@ -131,8 +131,8 @@
|
||||
|
||||
_contentObject = aContent;
|
||||
|
||||
[self _selectionDidChange];
|
||||
[self didChangeValueForKey:@"contentObject"];
|
||||
[self _selectionDidChange];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -323,22 +323,12 @@
|
||||
@ignore
|
||||
*/
|
||||
- (void)_selectionDidChange
|
||||
{
|
||||
[self _selectionDidChangeNotify:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
*/
|
||||
- (void)_selectionDidChangeNotify:(BOOL)notify
|
||||
{
|
||||
if (_selection === undefined || _selection === nil)
|
||||
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
|
||||
|
||||
[_selection controllerDidChange];
|
||||
|
||||
if (notify)
|
||||
[self didChangeValueForKey:@"selection"];
|
||||
[self didChangeValueForKey:@"selection"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -676,21 +666,21 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
var count = [theValues count];
|
||||
|
||||
if (!count)
|
||||
return CPNoSelectionMarker;
|
||||
value = CPNoSelectionMarker;
|
||||
else if (count === 1)
|
||||
value = [theValues objectAtIndex:0];
|
||||
else
|
||||
{
|
||||
if ([_controller alwaysUsesMultipleValuesMarker])
|
||||
return CPMultipleValuesMarker;
|
||||
value = CPMultipleValuesMarker;
|
||||
else
|
||||
{
|
||||
value = [theValues objectAtIndex:0];
|
||||
|
||||
for (var i = 0, count = [theValues count]; i < count; i++)
|
||||
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
|
||||
{
|
||||
if (![value isEqual:[theValues objectAtIndex:i]])
|
||||
return CPMultipleValuesMarker;
|
||||
value = CPMultipleValuesMarker;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -703,21 +693,8 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
|
||||
|
||||
- (id)valueForKeyPath:(CPString)theKeyPath
|
||||
{
|
||||
// If valueForKeyPath fails because of an undefined key, return CPNotApplicableMarker
|
||||
var value;
|
||||
|
||||
try
|
||||
{
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
}
|
||||
catch (ex)
|
||||
{
|
||||
if ([ex name] === CPUndefinedKeyException)
|
||||
value = CPNotApplicableMarker;
|
||||
else
|
||||
throw ex;
|
||||
}
|
||||
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
|
||||
value = [self _controllerMarkerForValues:values];
|
||||
|
||||
[_cachedValues setObject:value forKey:theKeyPath];
|
||||
|
||||
|
||||
@@ -1458,44 +1458,6 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
|
||||
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
|
||||
}
|
||||
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
modifierFlags = [anEvent modifierFlags];
|
||||
|
||||
// Check for the key events manually, as opposed to waiting for CPWindow to sent the actual action message
|
||||
// in _processKeyboardUIKey:, because we might not want to handle the arrow events.
|
||||
|
||||
if (character !== CPRightArrowFunctionKey && character !== CPLeftArrowFunctionKey)
|
||||
return [super keyDown:anEvent];
|
||||
|
||||
var rows = [self selectedRowIndexes],
|
||||
indexes = [],
|
||||
items = [];
|
||||
|
||||
[rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var i = 0,
|
||||
c = [indexes count];
|
||||
|
||||
for (; i < c; i++)
|
||||
items.push([self itemAtRow:indexes[i]]);
|
||||
|
||||
|
||||
if (character === CPRightArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self expandItem:items[i]];
|
||||
}
|
||||
else if (character === CPLeftArrowFunctionKey)
|
||||
{
|
||||
for (var i = 0; i < c; i++)
|
||||
[self collapseItem:items[i]];
|
||||
}
|
||||
|
||||
[super keyDown:anEvent];
|
||||
}
|
||||
@end
|
||||
|
||||
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* CPPopover.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal.
|
||||
* Copyright 2011 Antoine Mercadal.
|
||||
*
|
||||
* 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 "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPView.j"
|
||||
@import "_CPAttachedWindow.j"
|
||||
|
||||
|
||||
CPPopoverBehaviorApplicationDefined = 0;
|
||||
CPPopoverBehaviorTransient = 1;
|
||||
CPPopoverBehaviorSemitransient = 2;
|
||||
|
||||
|
||||
var CPPopoverDelegate_popover_willShow_ = 1 << 0,
|
||||
CPPopoverDelegate_popover_didShow_ = 1 << 1,
|
||||
CPPopoverDelegate_popover_shouldClose_ = 1 << 2,
|
||||
CPPopoverDelegate_popover_willClose_ = 1 << 3,
|
||||
CPPopoverDelegate_popover_didClose_ = 1 << 4;
|
||||
|
||||
|
||||
/*! @ingroup appkit
|
||||
@class CPPopover
|
||||
|
||||
This class represent a widget that displays a attached
|
||||
view relative to another one.
|
||||
|
||||
Delegate can implement:
|
||||
– popoverShouldClose:(CPPopover)aPopOver
|
||||
– popoverWillShow:(CPPopover)aPopOver
|
||||
– popoverDidShow:(CPPopover)aPopOver
|
||||
– popoverWillClose:(CPPopover)aPopOver
|
||||
– popoverDidClose:(CPPopover)aPopOver
|
||||
*/
|
||||
@implementation CPPopover : CPResponder
|
||||
{
|
||||
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
|
||||
@outlet id _delegate @accessors(getter=delegate);
|
||||
|
||||
BOOL _animates @accessors(property=animates);
|
||||
BOOL _shown @accessors(getter=shown);
|
||||
int _appearance @accessors(property=appearance);
|
||||
int _behavior @accessors(getter=behavior);
|
||||
|
||||
BOOL _needsCompute;
|
||||
_CPAttachedWindow _attachedWindow;
|
||||
int _implementedDelegateMethods;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark INitialization
|
||||
|
||||
/*!
|
||||
Initialize the CPPopover witn default values
|
||||
|
||||
@returns anInitialized CPPopover
|
||||
*/
|
||||
- (CPPopover)init
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_animates = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_behavior = CPPopoverBehaviorApplicationDefined;
|
||||
_needsCompute = YES;
|
||||
_shown = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Getters / Setters
|
||||
|
||||
/*!
|
||||
Returns the current rect of the popover
|
||||
|
||||
@return CPRect represeting the frame of the popover
|
||||
*/
|
||||
- (CPRect)positionningRect
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [_attachedWindow frame];
|
||||
}
|
||||
|
||||
/*! Sets the frame of the popover
|
||||
@param aRect the desired frame
|
||||
*/
|
||||
- (void)setPositionningRect:(CPRect)aRect
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return;
|
||||
[_attachedWindow setFrame:aRect];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the popover's view
|
||||
|
||||
@return CPSize represeting the size of the popover's view
|
||||
*/
|
||||
- (CPRect)contentSize
|
||||
{
|
||||
if (!_attachedWindow || ![_attachedWindow isVisible])
|
||||
return nil;
|
||||
return [[_contentViewController view] frameSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the size of of the popover's view
|
||||
|
||||
@param aSize the desired size
|
||||
*/
|
||||
- (void)setContentSize:(CPSize)aSize
|
||||
{
|
||||
[[_contentViewController view] setFrameSize:aSize];
|
||||
}
|
||||
|
||||
/*!
|
||||
Indicates if CPPopover is visible
|
||||
|
||||
@returns YES if visible
|
||||
*/
|
||||
- (BOOL)shown
|
||||
{
|
||||
if (!_attachedWindow)
|
||||
return NO;
|
||||
return [_attachedWindow isVisible];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the behaviour of the CPPopover. It can be
|
||||
- CPPopoverBehaviorTransient: the popover will be close if another control outside the popover become the responder
|
||||
- CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover
|
||||
|
||||
@param aBehaviour the desired behaviour
|
||||
*/
|
||||
- (void)setBehaviour:(int)aBehaviour
|
||||
{
|
||||
if (_behavior == aBehaviour)
|
||||
return;
|
||||
|
||||
_behavior = aBehaviour;
|
||||
_needsCompute = YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate === aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidShow:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didShow_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverShouldClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_shouldClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverWillClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_willClose_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(popoverDidClose:)])
|
||||
_implementedDelegateMethods |= CPPopoverDelegate_popover_didClose_;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Positionning
|
||||
|
||||
/*!
|
||||
Show the popover
|
||||
|
||||
@param positioningRect if set, the popover will be positionned to a random rect relative to the window
|
||||
@param positioningView if set, the popover will be positioned relative to this view
|
||||
@param preferredEdge: CPRectEdge representing the prefered positionning.
|
||||
*/
|
||||
- (void)showRelativeToRect:(CPRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
|
||||
[_delegate popoverWillShow:self];
|
||||
|
||||
if (!_contentViewController)
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
|
||||
|
||||
if (_needsCompute)
|
||||
{
|
||||
var styleMask = (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : nil;
|
||||
_attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:styleMask];
|
||||
}
|
||||
|
||||
[_attachedWindow setAppearance:_appearance];
|
||||
[_attachedWindow setAnimates:_animates];
|
||||
[_attachedWindow setMovableByWindowBackground:NO];
|
||||
[_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]];
|
||||
[_attachedWindow setContentView:[_contentViewController view]];
|
||||
|
||||
if (positioningRect)
|
||||
[_attachedWindow positionRelativeToRect:positioningRect preferredEdge:preferredEdge];
|
||||
else if (positioningView)
|
||||
[_attachedWindow positionRelativeToView:positioningView preferredEdge:preferredEdge];
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:@"you must set positioningRect or positioningRect"];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
|
||||
[_delegate popoverDidShow:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Closes the popover
|
||||
*/
|
||||
- (void)close
|
||||
{
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
|
||||
if (![_delegate popoverShouldClose:self])
|
||||
return;
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
|
||||
[_delegate popoverWillClose:self];
|
||||
|
||||
[_attachedWindow close];
|
||||
|
||||
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
|
||||
[_delegate popoverDidClose:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action
|
||||
|
||||
/*!
|
||||
Close the popover
|
||||
|
||||
@param aSender the sender of the action
|
||||
*/
|
||||
- (IBAction)performClose:(id)aSender
|
||||
{
|
||||
[self close];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation CPPopover (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_needsCompute = [aCoder decodeIntForKey:@"_needsCompute"];
|
||||
_appearance = [aCoder decodeIntForKey:@"_appearance"];
|
||||
_animates = [aCoder decodeBoolForKey:@"_animates"];
|
||||
_contentViewController = [aCoder decodeObjectForKey:@"_contentViewController"];
|
||||
[self setDelegate:[aCoder decodeObjectForKey:@"_delegate"]];
|
||||
[self setBehaviour:[aCoder decodeIntForKey:@"_behavior"]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_behavior forKey:@"_behavior"];
|
||||
[aCoder encodeInt:_appearance forKey:@"_appearance"];
|
||||
[aCoder encodeBool:_needsCompute forKey:@"_needsCompute"];
|
||||
[aCoder encodeObject:_contentViewController forKey:@"_contentViewController"];
|
||||
[aCoder encodeObject:_delegate forKey:@"_delegate"];
|
||||
[aCoder encodeObject:_animates forKey:@"_animates"];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -34,12 +34,6 @@
|
||||
places scroll bars on the side of the view to allow the user to scroll and see the entire
|
||||
contents of the view.
|
||||
*/
|
||||
|
||||
var TIMER_INTERVAL = 0.2,
|
||||
CPScrollViewDelegate_scrollViewWillScroll_ = 1 << 0,
|
||||
CPScrollViewDelegate_scrollViewDidScroll_ = 1 << 1;
|
||||
|
||||
|
||||
@implementation CPScrollView : CPView
|
||||
{
|
||||
CPClipView _contentView;
|
||||
@@ -47,9 +41,6 @@ var TIMER_INTERVAL = 0.2,
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
|
||||
id _delegate;
|
||||
CPTimer _scrollTimer;
|
||||
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
@@ -57,8 +48,7 @@ var TIMER_INTERVAL = 0.2,
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
CPInteger _recursionCount;
|
||||
CPInteger _implementedDelegateMethods;
|
||||
int _recursionCount;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
@@ -96,6 +86,7 @@ var TIMER_INTERVAL = 0.2,
|
||||
_borderType = CPNoBorder;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
_headerClipView = [[CPClipView alloc] init];
|
||||
@@ -106,37 +97,11 @@ var TIMER_INTERVAL = 0.2,
|
||||
|
||||
[self setHasVerticalScroller:YES];
|
||||
[self setHasHorizontalScroller:YES];
|
||||
|
||||
_delegate = nil;
|
||||
_scrollTimer = nil;
|
||||
_implementedDelegateMethods = 0;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (aDelegate === _delegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
_implementedDelegateMethods = 0;
|
||||
|
||||
if (_delegate === nil)
|
||||
return;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
|
||||
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewWillScroll_;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)])
|
||||
_implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
|
||||
}
|
||||
// Calculating Layout
|
||||
|
||||
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
@@ -690,8 +655,6 @@ var TIMER_INTERVAL = 0.2,
|
||||
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
}
|
||||
|
||||
@@ -722,8 +685,6 @@ var TIMER_INTERVAL = 0.2,
|
||||
default: contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
|
||||
}
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
||||
}
|
||||
@@ -1001,8 +962,6 @@ var TIMER_INTERVAL = 0.2,
|
||||
extraX = contentBounds.origin.x - constrainedOrigin.x,
|
||||
extraY = contentBounds.origin.y - constrainedOrigin.y;
|
||||
|
||||
[self _sendDelegateMessages];
|
||||
|
||||
[_contentView scrollToPoint:constrainedOrigin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
|
||||
|
||||
@@ -1070,35 +1029,6 @@ var TIMER_INTERVAL = 0.2,
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
|
||||
}
|
||||
|
||||
- (void)_sendDelegateMessages
|
||||
{
|
||||
if (_implementedDelegateMethods == 0)
|
||||
return;
|
||||
|
||||
if (!_scrollTimer)
|
||||
{
|
||||
[self _scrollViewWillScroll];
|
||||
_scrollTimer = [CPTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(_scrollViewDidScroll) userInfo:nil repeats:YES];
|
||||
}
|
||||
else
|
||||
[_scrollTimer setFireDate:[CPDate dateWithTimeIntervalSinceNow:TIMER_INTERVAL]];
|
||||
}
|
||||
|
||||
- (void)_scrollViewWillScroll
|
||||
{
|
||||
if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewWillScroll_)
|
||||
[_delegate scrollViewWillScroll:self];
|
||||
}
|
||||
|
||||
- (void)_scrollViewDidScroll
|
||||
{
|
||||
[_scrollTimer invalidate];
|
||||
_scrollTimer = nil;
|
||||
|
||||
if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewDidScroll_)
|
||||
[_delegate scrollViewDidScroll:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
@@ -1149,9 +1079,6 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
|
||||
|
||||
_delegate = nil;
|
||||
_scrollTimer = nil;
|
||||
_implementedDelegateMethods = 0;
|
||||
// Due to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(_updateCornerAndHeaderView) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
|
||||
@@ -457,9 +457,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
if (type === CPLeftMouseDragged)
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -45,7 +45,6 @@ CPSoundPlayBackStatePause = 2;
|
||||
CPString _name @accessors(property=name);
|
||||
id _delegate @accessors(property=delegate);
|
||||
|
||||
BOOL _playRequestBeforeLoad;
|
||||
HTMLAudioElement _audioTag;
|
||||
int _loadStatus;
|
||||
int _playBackStatus;
|
||||
@@ -62,7 +61,6 @@ CPSoundPlayBackStatePause = 2;
|
||||
_loops = NO;
|
||||
_audioTag = document.createElement("audio");
|
||||
_audioTag.preload = YES;
|
||||
_playRequestBeforeLoad = NO;
|
||||
|
||||
_audioTag.addEventListener("canplay", function()
|
||||
{
|
||||
@@ -140,12 +138,6 @@ CPSoundPlayBackStatePause = 2;
|
||||
- (void)_soundDidload
|
||||
{
|
||||
_loadStatus = CPSoundLoadStateCanBePlayed;
|
||||
|
||||
if (_playRequestBeforeLoad)
|
||||
{
|
||||
_playRequestBeforeLoad = NO;
|
||||
[self play];
|
||||
}
|
||||
}
|
||||
|
||||
/*! @ignore
|
||||
@@ -175,12 +167,6 @@ CPSoundPlayBackStatePause = 2;
|
||||
*/
|
||||
- (BOOL)play
|
||||
{
|
||||
if (_loadStatus === CPSoundLoadStateLoading)
|
||||
{
|
||||
_playRequestBeforeLoad = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|
||||
|| (_playBackStatus === CPSoundPlayBackStatePlay))
|
||||
return NO;
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* CPString+Additions.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Randy Luecke
|
||||
* Copyright 2011, RCLConcepts, LLC.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
AppKit adds two methods to the CPString class to support drawing string directly in an CPView.
|
||||
|
||||
AppKit also adds similar methods to CPAttributedString.
|
||||
The two drawing methods draw a string object with a single set of attributes that apply to the entire string.
|
||||
To draw a string with multiple attributes, such as multiple text fonts, you must use an attributed string.
|
||||
*/
|
||||
@implementation CPString (AppKitAdditions)
|
||||
|
||||
/*!
|
||||
Draws a string in the current graphics context.
|
||||
This method applies the attributes to the entier string
|
||||
and displays it on a single "infinately long" line.
|
||||
|
||||
@param aPoint - The starting point to draw the string
|
||||
@param attributes - the dictionary of attributes to apply to the string
|
||||
*/
|
||||
- (void)drawAtPoint:(CGPoint)aPoint withAttributes:(CPDictionary)attributes
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
run = _CTRunCreate([self copy], attributes);
|
||||
|
||||
CGContextSetTextPosition(context, aPoint.x, aPoint.y);
|
||||
CTRunDraw(run, context, nil);
|
||||
}
|
||||
|
||||
/*!
|
||||
Draws a string in the current graphics context.
|
||||
This method applies the attributes to the entier string
|
||||
and displays it within the given rect.
|
||||
|
||||
@param aRect - The rect for which the string should be drawn into
|
||||
@param attributes - the dictionary of attributes to apply to the string
|
||||
*/
|
||||
- (void)drawInRect:(CGRect)aRect withAttributes:(CPDictionary)attributes
|
||||
{
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
string = [[CPAttributedString alloc] initWithString:self attributes:attributes];
|
||||
frameSetter = CTFramesetterCreateWithAttributedString(string),
|
||||
path = CGPathCreateMutable();
|
||||
|
||||
CGPathAddRect(path, nil, aRect);
|
||||
|
||||
var frame = CTFramesetterCreateFrame(frameSetter, CPMakeRange(0, [string length]), path, nil);
|
||||
|
||||
CTFrameDraw(frame, context);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -332,18 +332,18 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
Example:
|
||||
@code
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@endcode
|
||||
@code
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
@endcode
|
||||
|
||||
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
|
||||
@code
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
@endcode
|
||||
@code
|
||||
[someView setSomething:x];
|
||||
[tableColumn setDataView:someView];
|
||||
@endcode
|
||||
|
||||
@note You should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
@note you should implement CPKeyedArchiving otherwise you might see unexpected results.
|
||||
This is done by adding the following methods to your class:
|
||||
@endnote
|
||||
|
||||
@@ -380,7 +380,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
}
|
||||
@endcode
|
||||
|
||||
@section Theming
|
||||
@section Themeing
|
||||
|
||||
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
|
||||
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
|
||||
|
||||
@@ -323,7 +323,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
|
||||
{
|
||||
_tableViewFlags = 0;
|
||||
_lastSelectedRow = -1;
|
||||
_clickedRow = -1;
|
||||
|
||||
_selectedColumnIndexes = [CPIndexSet indexSet];
|
||||
_selectedRowIndexes = [CPIndexSet indexSet];
|
||||
@@ -2771,7 +2770,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
*/
|
||||
- (BOOL)canDragRowsWithIndexes:(CPIndexSet)rowIndexes atPoint:(CGPoint)mouseDownPoint
|
||||
{
|
||||
return [rowIndexes count] > 0 && [self numberOfRows] > 0;
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -3545,16 +3544,16 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
|
||||
var exposedRows = [self _unboundedRowsInRect:aRect],
|
||||
firstRow = FLOOR(exposedRows.location / colorCount) * colorCount,
|
||||
lastRow = CPMaxRange(exposedRows),
|
||||
colorIndex = 0,
|
||||
groupRowRects = [];
|
||||
groupRowRects = [],
|
||||
row = exposedRows.location;
|
||||
|
||||
//loop through each color so we only draw once for each color
|
||||
while (colorIndex < colorCount)
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
for (var row = firstRow + colorIndex; row <= lastRow; row += colorCount)
|
||||
for (var row = colorIndex; row <= lastRow; row += colorCount)
|
||||
{
|
||||
// if it's not a group row draw it otherwise we draw it later
|
||||
if (![_groupRows containsIndex:row])
|
||||
@@ -4610,7 +4609,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
|
||||
}
|
||||
_wasSelectionBroken = true;
|
||||
}
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastIndex])))
|
||||
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex])))
|
||||
{
|
||||
shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex];
|
||||
_wasSelectionBroken = false;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#import "../Foundation/Ref.h"
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
@import "CPCompatibility.j"
|
||||
@@ -85,11 +83,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
CPString _placeholderString;
|
||||
CPString _stringValue;
|
||||
id _placeholderString;
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPString _textDidChangeValue;
|
||||
|
||||
// NS-style Display Properties
|
||||
CPTextFieldBezelStyle _bezelStyle;
|
||||
BOOL _isBordered;
|
||||
@@ -169,8 +168,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), _CGInsetMake(3.0, 3.0, 3.0, 3.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"border-inset", @"bezel-color"]];
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -482,17 +481,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self setNeedsLayout];
|
||||
|
||||
_isEditing = NO;
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement],
|
||||
var string = [self stringValue],
|
||||
element = [self _inputElement],
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
// generate the font metric
|
||||
[font _getMetrics];
|
||||
|
||||
element.value = _stringValue;
|
||||
element.value = string;
|
||||
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
|
||||
element.style.font = [font cssString];
|
||||
element.style.zIndex = 1000;
|
||||
@@ -507,32 +506,31 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
var contentRect = [self contentRectForBounds:[self bounds]],
|
||||
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"],
|
||||
lineHeight = [font defaultLineHeightForFont];
|
||||
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
|
||||
|
||||
switch (verticalAlign)
|
||||
{
|
||||
case CPTopVerticalTextAlignment:
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
|
||||
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
|
||||
break;
|
||||
|
||||
case CPCenterVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMidY(contentRect) - (lineHeight / 2)) + "px";
|
||||
var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px";
|
||||
break;
|
||||
|
||||
case CPBottomVerticalTextAlignment:
|
||||
var topPoint = (_CGRectGetMaxY(contentRect) - lineHeight) + "px";
|
||||
var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px";
|
||||
break;
|
||||
|
||||
default:
|
||||
var topPoint = _CGRectGetMinY(contentRect) + "px";
|
||||
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px";
|
||||
break;
|
||||
}
|
||||
|
||||
element.style.top = topPoint;
|
||||
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
|
||||
element.style.width = _CGRectGetWidth(contentRect) + "px";
|
||||
element.style.height = lineHeight + "px";
|
||||
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size
|
||||
|
||||
_DOMElement.appendChild(element);
|
||||
|
||||
@@ -550,6 +548,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
@@ -572,33 +572,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
[self unsetThemeState:CPThemeStateEditing];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement],
|
||||
error = @"";
|
||||
|
||||
// If there is a formatter, always give it a chance to reject the resignation,
|
||||
// even if the value has not changed.
|
||||
if ([self _valueIsValid:element.value] === NO)
|
||||
{
|
||||
[self setThemeState:CPThemeStateEditing];
|
||||
element.focus();
|
||||
return NO;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Cache the formatted string
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
_willBecomeFirstResponderByClick = NO;
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
|
||||
[self setNeedsLayout];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
if ([self stringValue] !== element.value)
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
|
||||
if (CPTextFieldInputIsActive)
|
||||
@@ -626,35 +610,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
#endif
|
||||
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_valueIsValid:(CPString)aValue
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var error = @"";
|
||||
|
||||
if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO)
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
if (_isEditing)
|
||||
{
|
||||
var acceptInvalidValue = NO;
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
|
||||
acceptInvalidValue = [_delegate control:self didFailToFormatString:[self _inputElement] errorDescription:error];
|
||||
|
||||
if (acceptInvalidValue === NO)
|
||||
return NO;
|
||||
if ([self sendsActionOnEndEditing])
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
#endif
|
||||
[self textDidBlur:[CPNotification notificationWithName:CPTextFieldDidBlurNotification object:self userInfo:nil]];
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -719,14 +685,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var oldValue = [self stringValue];
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
|
||||
var newValue = [self _inputElement].value;
|
||||
|
||||
if (newValue !== _stringValue)
|
||||
if (oldValue !== [self stringValue])
|
||||
{
|
||||
[self _setStringValue:newValue];
|
||||
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
@@ -736,13 +699,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
// CPTextField uses an HTML input element to take the input so we need to
|
||||
// propagate the dom event so the element is updated. This has to be done
|
||||
// before interpretKeyEvents: though so individual commands have a chance
|
||||
@@ -771,53 +735,26 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if ([self _valueIsValid:_stringValue])
|
||||
if (_isEditing)
|
||||
{
|
||||
// If _isEditing == YES then the target action can also be called via
|
||||
// resignFirstResponder, and it is possible that the target action
|
||||
// itself will change this textfield's responder status, so start by
|
||||
// setting the _isEditing flag to NO to prevent the target action being
|
||||
// called twice (once below and once from resignFirstResponder).
|
||||
if (_isEditing)
|
||||
{
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
// If there is no target action, or the sendAction call returns
|
||||
// success.
|
||||
if (![self action] || [self sendAction:[self action] to:[self target]])
|
||||
{
|
||||
[self selectAll:nil];
|
||||
}
|
||||
_isEditing = NO;
|
||||
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
[self selectText:nil];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
|
||||
}
|
||||
|
||||
- (void)insertNewlineIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
[self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
|
||||
}
|
||||
var oldValue = [self stringValue];
|
||||
|
||||
- (void)insertTabIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
[self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
|
||||
}
|
||||
[self _inputElement].value += CPNewlineCharacter;
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
|
||||
- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var oldValue = _stringValue,
|
||||
range = [self selectedRange],
|
||||
element = [self _inputElement];
|
||||
|
||||
element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter];
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
// NOTE: _stringValue is now the current input element value
|
||||
if (oldValue !== _stringValue)
|
||||
if (oldValue !== [self stringValue])
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
@@ -827,8 +764,25 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
- (void)insertTabIgnoringFieldEditor:(id)sender
|
||||
{
|
||||
var oldValue = [self stringValue];
|
||||
|
||||
[self _inputElement].value += CPTabCharacter;
|
||||
[self _setStringValue:[self _inputElement].value];
|
||||
|
||||
if (oldValue !== [self stringValue])
|
||||
{
|
||||
if (!_isEditing)
|
||||
{
|
||||
_isEditing = YES;
|
||||
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
|
||||
}
|
||||
|
||||
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
@@ -859,8 +813,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[super textDidChange:note];
|
||||
}
|
||||
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string in the text field.
|
||||
Returns the string the text field.
|
||||
*/
|
||||
- (id)objectValue
|
||||
{
|
||||
@@ -869,84 +830,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
This should only be invoked when the underlying text element's value has changed.
|
||||
Sets the internal string value without updating the value in the input element
|
||||
*/
|
||||
- (BOOL)_setStringValue:(CPString)aValue
|
||||
- (void)_setStringValue:(id)aValue
|
||||
{
|
||||
return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
Sets the internal string value without updating the value in the input element.
|
||||
If there is a formatter and formatting fails, returns NO. Otherwise returns YES.
|
||||
*/
|
||||
- (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
|
||||
{
|
||||
_stringValue = aValue;
|
||||
|
||||
var objectValue = aValue,
|
||||
formatter = [self formatter],
|
||||
result = YES;
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
var object = nil;
|
||||
|
||||
if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError])
|
||||
objectValue = object;
|
||||
else
|
||||
{
|
||||
objectValue = undefined; // Mark the value as invalid
|
||||
result = NO;
|
||||
}
|
||||
|
||||
isNewValue |= objectValue !== [super objectValue];
|
||||
}
|
||||
|
||||
if (isNewValue)
|
||||
{
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:objectValue];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
return result;
|
||||
[self willChangeValueForKey:@"objectValue"];
|
||||
[super setObjectValue:String(aValue)];
|
||||
[self _updatePlaceholderState];
|
||||
[self didChangeValueForKey:@"objectValue"];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
var formatter = [self formatter];
|
||||
|
||||
if (formatter)
|
||||
{
|
||||
// If there is a formatter, make sure the object value can be formatted successfully
|
||||
var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
|
||||
|
||||
if (formattedString === nil)
|
||||
{
|
||||
var value = nil;
|
||||
|
||||
// Formatting failed, get an "empty" object by formatting an empty string.
|
||||
// If that fails, the value is undefined.
|
||||
if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
|
||||
value = undefined;
|
||||
|
||||
[super setObjectValue:value];
|
||||
}
|
||||
}
|
||||
|
||||
_stringValue = [self stringValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
[self _inputElement].value = _stringValue;
|
||||
|
||||
[self _inputElement].value = aValue;
|
||||
#endif
|
||||
|
||||
[self _updatePlaceholderState];
|
||||
@@ -954,7 +855,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
if ((!_stringValue || _stringValue.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
var string = [self stringValue];
|
||||
|
||||
if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
@@ -1020,8 +923,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"],
|
||||
lineBreakMode = [self lineBreakMode],
|
||||
text = (_stringValue || @" "),
|
||||
textSize = CGSizeMakeCopy(frameSize),
|
||||
text = ([self stringValue] || @" "),
|
||||
textSize = _CGSizeMakeCopy(frameSize),
|
||||
font = [self currentValueForThemeAttribute:@"font"];
|
||||
|
||||
textSize.width -= contentInset.left + contentInset.right;
|
||||
@@ -1091,7 +994,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return;
|
||||
|
||||
var pasteboard = [CPPasteboard generalPasteboard],
|
||||
stringForPasting = [_stringValue substringWithRange:selectedRange];
|
||||
stringValue = [self stringValue],
|
||||
stringForPasting = [stringValue substringWithRange:selectedRange];
|
||||
|
||||
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
|
||||
[pasteboard setString:stringForPasting forType:CPStringPboardType];
|
||||
@@ -1121,8 +1025,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[self deleteBackward:sender];
|
||||
|
||||
var selectedRange = [self selectedRange],
|
||||
stringValue = [self stringValue],
|
||||
pasteString = [pasteboard stringForType:CPStringPboardType],
|
||||
newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
@@ -1136,8 +1041,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if ([[self window] firstResponder] !== self)
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
{
|
||||
@@ -1164,8 +1067,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
// fall through to the return
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return CPMakeRange(0, 0);
|
||||
}
|
||||
|
||||
@@ -1174,8 +1075,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (![[self window] firstResponder] === self)
|
||||
return;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
@@ -1204,8 +1103,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
catch (e)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)selectAll:(id)sender
|
||||
@@ -1223,7 +1120,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
selectedRange.location += 1;
|
||||
selectedRange.length -= 1;
|
||||
|
||||
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
var stringValue = [self stringValue],
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
|
||||
@@ -1291,8 +1189,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
if (!contentInset)
|
||||
return bounds;
|
||||
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
@@ -1317,14 +1217,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGInset)borderInset
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
|
||||
borderInset = [self currentValueForThemeAttribute:@"border-inset"];
|
||||
|
||||
return CGInsetUnion(bezelInset, borderInset);
|
||||
}
|
||||
|
||||
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
@@ -1382,7 +1274,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
string = [self placeholderString];
|
||||
else
|
||||
{
|
||||
string = _stringValue;
|
||||
string = [self stringValue];
|
||||
|
||||
if ([self isSecure])
|
||||
string = secureStringForString(string);
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeNamesByInheritance = [],
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -77,52 +76,6 @@ var CPThemesByName = { },
|
||||
return CPThemesByName[aName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of all loaded themes, in the order they were loaded.
|
||||
*/
|
||||
+ (CPArray)allThemeNames
|
||||
{
|
||||
return [CPThemeNamesByInheritance copy];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the closest matching theme for a given view or view class.
|
||||
The matching proceeds as follows:
|
||||
|
||||
- The default theme class name for the class is retrieved.
|
||||
- Starting with the last loaded theme and proceeding towards the default theme,
|
||||
each theme is checked to see if it defines that theme class.
|
||||
- If the theme defines the class name, that theme is returned.
|
||||
- If no themes match, the default theme is returned.
|
||||
|
||||
@param aViewOrClass The view or view class to match with a theme
|
||||
@return The first matching theme
|
||||
*/
|
||||
+ (CPTheme)themeForView:(id)aViewOrClass
|
||||
{
|
||||
var themeClass = nil;
|
||||
|
||||
if (class_isMetaClass(aViewOrClass.isa))
|
||||
themeClass = [aViewOrClass defaultThemeClass];
|
||||
else
|
||||
themeClass = [aViewOrClass themeClass];
|
||||
|
||||
if (themeClass)
|
||||
{
|
||||
var count = CPThemeNamesByInheritance.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var theme = CPThemesByName[CPThemeNamesByInheritance[count]];
|
||||
|
||||
if ([theme._attributes containsKey:themeClass])
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
@@ -133,9 +86,6 @@ var CPThemesByName = { },
|
||||
_attributes = [CPDictionary dictionary];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -349,9 +299,6 @@ var CPThemeNameKey = @"CPThemeNameKey",
|
||||
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
|
||||
|
||||
CPThemesByName[_name] = self;
|
||||
|
||||
if (![CPThemeNamesByInheritance containsObject:_name])
|
||||
CPThemeNamesByInheritance.push(_name);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -93,69 +93,65 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return "tokenfield";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
- (id)initWithFrame:(CPRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_selectedRange = CPMakeRange(0, 0);
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_tokenIndex = 0;
|
||||
|
||||
_cachedCompletions = [];
|
||||
_completionDelay = [CPTokenField defaultCompletionDelay];
|
||||
|
||||
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
|
||||
[self setBezeled:YES];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setObjectValue:[]];
|
||||
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
var frame = [self frame];
|
||||
|
||||
_tokenScrollView = [[CPScrollView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[_tokenScrollView setHasHorizontalScroller:NO];
|
||||
[_tokenScrollView setHasVerticalScroller:NO];
|
||||
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
var contentView = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
[contentView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_tokenScrollView setDocumentView:contentView];
|
||||
|
||||
[self addSubview:_tokenScrollView];
|
||||
|
||||
_cachedCompletions = [];
|
||||
|
||||
_autocompleteContainer = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, frame.size.width, 92.0)];
|
||||
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
|
||||
|
||||
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:_CGRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
|
||||
[_autocompleteScrollView setAutohidesScrollers:YES];
|
||||
[_autocompleteScrollView setHasHorizontalScroller:NO];
|
||||
[_autocompleteContainer addSubview:_autocompleteScrollView];
|
||||
|
||||
_autocompleteView = [[CPTableView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
|
||||
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
|
||||
[_autocompleteView addTableColumn:tableColumn];
|
||||
|
||||
[_autocompleteView setDataSource:self];
|
||||
[_autocompleteView setDelegate:self];
|
||||
[_autocompleteView setAllowsMultipleSelection:NO];
|
||||
[_autocompleteView setHeaderView:nil];
|
||||
[_autocompleteView setCornerView:nil];
|
||||
[_autocompleteView setRowHeight:30.0];
|
||||
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
|
||||
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
|
||||
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
|
||||
|
||||
[_autocompleteScrollView setDocumentView:_autocompleteView];
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = CONVENIENCE =
|
||||
// ===============
|
||||
@@ -163,16 +159,12 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
var indexOfSelectedItem = 0;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:0 indexOfSelectedItem:indexOfSelectedItem];
|
||||
#endif
|
||||
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:_tokenIndex indexOfSelectedItem:indexOfSelectedItem];
|
||||
|
||||
[_autocompleteView selectRowIndexes:[CPIndexSet indexSetWithIndex:indexOfSelectedItem] byExtendingSelection:NO];
|
||||
[_autocompleteView reloadData];
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
- (void)_autocompleteWithDOMEvent:(JSObject)DOMEvent
|
||||
{
|
||||
if (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting])
|
||||
@@ -226,8 +218,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self _autocompleteWithDOMEvent:nil];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (void)_selectToken:(_CPTokenFieldToken)token byExtendingSelection:(BOOL)extend
|
||||
{
|
||||
var indexOfToken = [[self _tokens] indexOfObject:token];
|
||||
@@ -378,10 +368,10 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
[self unsetThemeState:CPThemeStateEditing];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
[self _autocomplete];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
CPTokenFieldInputResigning = YES;
|
||||
@@ -664,7 +654,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
rowRect = [autocompleteView rectOfRow:index],
|
||||
owner = CPTokenFieldInputOwner;
|
||||
|
||||
if (rowRect && !CGRectContainsRect([clipView bounds], rowRect))
|
||||
if (rowRect && !CPRectContainsRect([clipView bounds], rowRect))
|
||||
[clipView scrollToPoint:[autocompleteView rectOfRow:index].origin];
|
||||
|
||||
if (aDOMEvent.keyCode === CPReturnKeyCode || aDOMEvent.keyCode === CPTabKeyCode)
|
||||
@@ -754,7 +744,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
else if (aDOMEvent.keyCode === CPDeleteKeyCode)
|
||||
{
|
||||
// Highlight the previous token if backspace was pressed in an empty input element or re-show the completions view
|
||||
if (CPTokenFieldDOMInputElement.value.length === 0)
|
||||
if (CPTokenFieldDOMInputElement.value == @"")
|
||||
{
|
||||
[self _hideCompletions];
|
||||
|
||||
@@ -874,15 +864,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
#endif
|
||||
|
||||
// In the context of a token field, it is empty when there are no tokens
|
||||
- (void)_updatePlaceholderState
|
||||
{
|
||||
if (([[self _tokens] count] === 0) && ![self hasThemeState:CPThemeStateEditing])
|
||||
[self setThemeState:CPTextFieldStatePlaceholder];
|
||||
else
|
||||
[self unsetThemeState:CPTextFieldStatePlaceholder];
|
||||
}
|
||||
|
||||
// - (void)setTokenStyle: (NSTokenStyle) style;
|
||||
// - (NSTokenStyle)tokenStyle;
|
||||
//
|
||||
@@ -965,9 +946,9 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// Manually sizeToFit because CPTableView's sizeToFit doesn't work properly
|
||||
[_autocompleteContainer setHidden:NO];
|
||||
var frameOrigin = [self convertPoint:[self bounds].origin toView:[_autocompleteContainer superview]];
|
||||
[_autocompleteContainer setFrameOrigin:_CGPointMake(frameOrigin.x, frameOrigin.y + frame.size.height)];
|
||||
[_autocompleteContainer setFrameSize:_CGSizeMake(_CGRectGetWidth([self bounds]), 92.0)];
|
||||
[_autocompleteScrollView setFrameSize:_CGSizeMake([_autocompleteContainer frame].size.width - 2.0, 90.0)];
|
||||
[_autocompleteContainer setFrameOrigin:CPPointMake(frameOrigin.x, frameOrigin.y + frame.size.height)];
|
||||
[_autocompleteContainer setFrameSize:CPSizeMake(CPRectGetWidth([self bounds]), 92.0)];
|
||||
[_autocompleteScrollView setFrameSize:CPSizeMake([_autocompleteContainer frame].size.width - 2.0, 90.0)];
|
||||
}
|
||||
else
|
||||
[_autocompleteContainer setHidden:YES];
|
||||
@@ -977,11 +958,11 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return;
|
||||
|
||||
// Move each token into the right position.
|
||||
var contentRect = _CGRectMakeCopy([contentView bounds]),
|
||||
var contentRect = CGRectMakeCopy([contentView bounds]),
|
||||
contentOrigin = contentRect.origin,
|
||||
contentSize = contentRect.size,
|
||||
offset = _CGPointMake(contentOrigin.x, contentOrigin.y),
|
||||
spaceBetweenTokens = _CGSizeMake(2.0, 2.0),
|
||||
offset = CPPointMake(contentOrigin.x, contentOrigin.y),
|
||||
spaceBetweenTokens = CPSizeMake(2.0, 2.0),
|
||||
isEditing = [[self window] firstResponder] == self,
|
||||
tokenToken = [_CPTokenFieldToken new];
|
||||
|
||||
@@ -992,7 +973,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
var fitAndFrame = function(width, height)
|
||||
{
|
||||
var r = _CGRectMake(0, 0, width, height);
|
||||
var r = CGRectMake(0, 0, width, height);
|
||||
|
||||
if (offset.x + width >= contentSize.width && offset.x > contentOrigin.x)
|
||||
{
|
||||
@@ -1005,7 +986,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
// Make sure the frame fits.
|
||||
if (CGRectGetHeight([contentView bounds]) < offset.y + height)
|
||||
[contentView setFrame:_CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + height)];
|
||||
[contentView setFrame:CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + height)];
|
||||
|
||||
offset.x += width + spaceBetweenTokens.width;
|
||||
|
||||
@@ -1014,7 +995,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
|
||||
var placeEditor = function(useRemainingWidth)
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement],
|
||||
textWidth = 1;
|
||||
|
||||
@@ -1024,7 +1004,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// without clipping. Since different fonts might have different sizes of "X" this
|
||||
// solution is not ideal, but it works.
|
||||
textWidth = [(element.value || @"") + "X" sizeWithFont:[self font]].width;
|
||||
|
||||
if (useRemainingWidth)
|
||||
textWidth = MAX(contentSize.width - offset.x - 1, textWidth);
|
||||
}
|
||||
@@ -1039,7 +1018,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
// When editing, always scroll to the cursor.
|
||||
if (_selectedRange.length == 0)
|
||||
[[_tokenScrollView documentView] scrollRectToVisible:inputFrame];
|
||||
#endif
|
||||
}
|
||||
|
||||
for (var i = 0, count = [tokens count]; i < count; i++)
|
||||
@@ -1066,7 +1044,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
if (isEditing && CPMaxRange(_selectedRange) >= [tokens count])
|
||||
placeEditor(true);
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
// Hide the editor if there are selected tokens, but still keep it active
|
||||
// so we can continue using our standard keyboard handling events.
|
||||
if (isEditing && _selectedRange.length)
|
||||
@@ -1074,27 +1051,24 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
[self _inputElement].style.left = "-10000px";
|
||||
[self _inputElement].focus();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Trim off any excess height downwards.
|
||||
if (CGRectGetHeight([contentView bounds]) > offset.y + tokenHeight)
|
||||
[contentView setFrame:_CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + tokenHeight)];
|
||||
[contentView setFrame:CGRectMake(0, 0, CGRectGetWidth([_tokenScrollView bounds]), offset.y + tokenHeight)];
|
||||
|
||||
if (_shouldScrollTo !== CPScrollDestinationNone)
|
||||
{
|
||||
// Only carry out the scroll if the cursor isn't visible.
|
||||
if (!(isEditing && _selectedRange.length == 0))
|
||||
{
|
||||
var scrollToToken = _shouldScrollTo;
|
||||
|
||||
var scrollToToken = _shouldScrollTo;
|
||||
if (scrollToToken === CPScrollDestinationLeft)
|
||||
scrollToToken = tokens[_selectedRange.location]
|
||||
else if (scrollToToken === CPScrollDestinationRight)
|
||||
scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
|
||||
|
||||
[self _scrollTokenViewToVisible:scrollToToken];
|
||||
}
|
||||
|
||||
_shouldScrollTo = CPScrollDestinationNone;
|
||||
}
|
||||
}
|
||||
@@ -1149,7 +1123,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
|
||||
{
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:_tokenIndex indexOfSelectedItem:selectedIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -1210,11 +1184,11 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
return "tokenfield-token";
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
- (id)initWithFrame:(CPRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:_CGRectMakeZero()];
|
||||
_deleteButton = [[_CPTokenFieldTokenCloseButton alloc] initWithFrame:CPRectMakeZero()];
|
||||
[self addSubview:_deleteButton];
|
||||
|
||||
[self setEditable:NO];
|
||||
@@ -1275,7 +1249,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
buttonOffset = [_deleteButton currentValueForThemeAttribute:@"offset"],
|
||||
buttonSize = [_deleteButton currentValueForThemeAttribute:@"min-size"];
|
||||
|
||||
[_deleteButton setFrame:_CGRectMake(_CGRectGetMaxX(frame) - buttonOffset.x, _CGRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
[_deleteButton setFrame:CPRectMake(CPRectGetMaxX(frame) - buttonOffset.x, CPRectGetMinY(frame) + buttonOffset.y, buttonSize.width, buttonSize.height)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1318,37 +1292,3 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
|
||||
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
|
||||
|
||||
@implementation CPTokenField (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
|
||||
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
|
||||
|
||||
[self _init];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
|
||||
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1015,7 +1015,7 @@ var TOP_MARGIN = 5.0,
|
||||
_labelSize = [_labelField frame].size;
|
||||
|
||||
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
|
||||
_maxSize = CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
|
||||
_maxSize = CGSizeMake(MIN(_labelSize.width, maxSize.width), 100000000.0);
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ var CPViewFlags = { },
|
||||
_DOMImageSizes = [];
|
||||
#endif
|
||||
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeState = CPThemeStateNormal;
|
||||
|
||||
[self setupViewFlags];
|
||||
@@ -2543,32 +2543,6 @@ setBoundsOrigin:
|
||||
return (_themeAttributes && _themeAttributes[aName] !== undefined);
|
||||
}
|
||||
|
||||
- (void)registerThemeValues:(CPArray)themeValues
|
||||
{
|
||||
for (var i = 0; i < themeValues.length; ++i)
|
||||
{
|
||||
var attributeValueState = themeValues[i],
|
||||
attribute = attributeValueState[0],
|
||||
value = attributeValueState[1],
|
||||
state = attributeValueState[2];
|
||||
|
||||
if (state)
|
||||
[self setValue:value forThemeAttribute:attribute inState:state];
|
||||
else
|
||||
[self setValue:value forThemeAttribute:attribute];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)registerThemeValues:(CPArray)themeValues inherit:(CPArray)inheritedValues
|
||||
{
|
||||
// Register inherited values first, then override those with the subtheme values.
|
||||
if (inheritedValues)
|
||||
[self registerThemeValues:inheritedValues];
|
||||
|
||||
if (themeValues)
|
||||
[self registerThemeValues:themeValues];
|
||||
}
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
|
||||
{
|
||||
return nil;
|
||||
@@ -2721,7 +2695,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
|
||||
|
||||
[self setupViewFlags];
|
||||
|
||||
_theme = [CPTheme themeForView:self];
|
||||
_theme = [CPTheme defaultTheme];
|
||||
_themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey];
|
||||
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
|
||||
_themeAttributes = {};
|
||||
|
||||
@@ -111,8 +111,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero(),
|
||||
value = [super currentValue];
|
||||
differenceFrame = _CGRectMakeZero();
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||
@@ -120,19 +119,19 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = _CGRectMakeZero();
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * value;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * value;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * value;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * value;
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
|
||||
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
|
||||
|
||||
[view setFrame:intermediateFrame];
|
||||
|
||||
// Update the view's alpha value
|
||||
var effect = [self _effect:dictionary];
|
||||
if (effect === CPViewAnimationFadeInEffect)
|
||||
[view setAlphaValue:1.0 * value];
|
||||
[view setAlphaValue:1.0 * progress];
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * value];
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||
|
||||
if (progress === 1.0)
|
||||
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
|
||||
@@ -480,7 +480,6 @@ CPTexturedBackgroundWindowMask
|
||||
[self close];
|
||||
|
||||
_platformWindow = aPlatformWindow;
|
||||
[_platformWindow setTitle:_title];
|
||||
|
||||
if (wasVisible)
|
||||
[self orderFront:self];
|
||||
@@ -1360,7 +1359,6 @@ CPTexturedBackgroundWindowMask
|
||||
_title = aTitle;
|
||||
|
||||
[_windowView setTitle:aTitle];
|
||||
[_platformWindow setTitle:_title];
|
||||
|
||||
[self _synchronizeMenuBarTitleWithWindowTitle];
|
||||
}
|
||||
@@ -2930,6 +2928,5 @@ CPCustomWindowShadowStyle = 3;
|
||||
@import "_CPHUDWindowView.j"
|
||||
@import "_CPBorderlessWindowView.j"
|
||||
@import "_CPBorderlessBridgeWindowView.j"
|
||||
@import "_CPAttachedWindowView.j"
|
||||
@import "CPDragServer.j"
|
||||
@import "CPView.j"
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* _CPAttachedWindowView.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Antoine Mercadal
|
||||
* Copyright 2011 <primalmotion@archipelproject.org>
|
||||
*
|
||||
* 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 "_CPWindowView.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ignore
|
||||
|
||||
A custom CPWindowView that manage border and cursor
|
||||
*/
|
||||
@implementation _CPAttachedWindowView : _CPWindowView
|
||||
{
|
||||
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
|
||||
float _arrowOffsetX @accessors(property=arrowOffsetX);
|
||||
float _arrowOffsetY @accessors(property=arrowOffsetY);
|
||||
int _appearance @accessors(property=appearance);
|
||||
unsigned _preferredEdge @accessors(property=preferredEdge);
|
||||
|
||||
CPSize _cursorSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the contentView frame from a given window frame
|
||||
|
||||
@param aFrameRect the window frame
|
||||
*/
|
||||
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy(aFrameRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
// return CGRectInset(contentRect, 20, 20);
|
||||
|
||||
contentRect.origin.x += 18;
|
||||
contentRect.origin.y += 17;
|
||||
contentRect.size.width -= 35;
|
||||
contentRect.size.height -= 37;
|
||||
|
||||
return contentRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Compute the window frame from a given contentView frame
|
||||
|
||||
@param aContentRect the contentView frame
|
||||
*/
|
||||
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
|
||||
{
|
||||
var frameRect = CGRectMakeCopy(aContentRect);
|
||||
|
||||
// @todo change border art and remove this pixel perfect adaptation
|
||||
//return CGRectOffset(frameRect, 20, 20);
|
||||
|
||||
frameRect.origin.x -= 18;
|
||||
frameRect.origin.y -= 17;
|
||||
frameRect.size.width += 35;
|
||||
frameRect.size.height += 37;
|
||||
return frameRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize the _CPWindowView
|
||||
*/
|
||||
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
_arrowOffsetX = 0.0;
|
||||
_arrowOffsetY = 0.0;
|
||||
|
||||
// @TODO: make this themable
|
||||
_useGlowingEffect = YES;
|
||||
_appearance = CPPopoverAppearanceMinimal;
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Hide the cursor
|
||||
*/
|
||||
- (void)hideCursor
|
||||
{
|
||||
_cursorSize = CPSizeMakeZero();
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Show the cursor
|
||||
*/
|
||||
- (void)showCursor
|
||||
{
|
||||
_cursorSize = CPSizeMake(15, 10);
|
||||
[self setNeedsDisplay:YES];
|
||||
_mouseDownPressed = NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the view
|
||||
*/
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
radius = 5,
|
||||
arrowWidth = _cursorSize.width,
|
||||
arrowHeight = _cursorSize.height,
|
||||
strokeWidth = 1,
|
||||
strokeColor,
|
||||
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
|
||||
shadowSize = CGSizeMake(0, 7),
|
||||
shadowBlur = 15,
|
||||
gradient;
|
||||
|
||||
if (_appearance == CPPopoverAppearanceMinimal)
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(254.0 / 255), (254.0 / 255), (254.0 / 255), 0.93,
|
||||
(231.0 / 255), (231.0 / 255), (231.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"B8B8B8"];
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(38.0 / 255), (38.0 / 255), (38.0 / 255), 0.93,
|
||||
(18.0 / 255), (18.0 / 255), (18.0 / 255), 0.93], [0,1], 2);
|
||||
strokeColor = [CPColor colorWithHexString:@"222222"];
|
||||
}
|
||||
|
||||
// fix rect to take care of stroke and shadow
|
||||
aRect.origin.x += strokeWidth + shadowBlur;
|
||||
aRect.origin.y += strokeWidth + (shadowBlur + shadowSize.height / 2);
|
||||
aRect.size.width -= (strokeWidth * 2) + (shadowBlur * 2);
|
||||
aRect.size.height -= (strokeWidth * 2) + (shadowBlur * 2 + shadowSize.height);
|
||||
|
||||
CGContextSetStrokeColor(context, strokeColor);
|
||||
CGContextSetLineWidth(context, strokeWidth);
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
|
||||
CGContextDrawLinearGradient(context, gradient, CGPointMake(CPRectGetMidX(aRect), 0.0), CGPointMake(CPRectGetMidX(aRect), aRect.size.height), 0);
|
||||
|
||||
|
||||
var xMin = _CGRectGetMinX(aRect),
|
||||
xMax = _CGRectGetMaxX(aRect),
|
||||
yMin = _CGRectGetMinY(aRect),
|
||||
yMax = _CGRectGetMaxY(aRect);
|
||||
|
||||
// draw!
|
||||
switch (_preferredEdge)
|
||||
{
|
||||
case CPMinXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// arrow CPMinXEdge
|
||||
CGContextAddLineToPoint(context, xMax, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY - (arrowHeight - 2));
|
||||
CGContextAddLineToPoint(context, aRect.size.width + arrowHeight + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.size.width + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 + (arrowWidth / 2)) + aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
break;
|
||||
|
||||
case CPMaxXEdge:
|
||||
// origin ne
|
||||
CGContextMoveToPoint(context, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
|
||||
// arrow CPMaxXEdge
|
||||
CGContextAddLineToPoint(context, xMin, (aRect.size.height / 2 + (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
CGContextAddLineToPoint(context, aRect.origin.x - arrowHeight + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 - (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
break;
|
||||
|
||||
case CPMaxYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
|
||||
// arrow CPMaxYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX - (arrowWidth / 2), yMin);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y - arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
break;
|
||||
|
||||
case CPMinYEdge:
|
||||
// origin nw
|
||||
CGContextMoveToPoint(context, xMin, yMin + yMin);
|
||||
|
||||
// nw
|
||||
CGContextAddLineToPoint(context, xMin, yMin + radius);
|
||||
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
|
||||
|
||||
// ne
|
||||
CGContextAddLineToPoint(context, xMax - radius, yMin);
|
||||
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
|
||||
|
||||
// se
|
||||
CGContextAddLineToPoint(context, xMax, yMax - radius);
|
||||
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
|
||||
|
||||
// arrow CPMinYEdge
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX , yMax);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + arrowHeight + _arrowOffsetY);
|
||||
CGContextAddLineToPoint(context, (aRect.size.width / 2) - (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + _arrowOffsetY);
|
||||
|
||||
// sw
|
||||
CGContextAddLineToPoint(context, xMin + radius, yMax);
|
||||
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
|
||||
break;
|
||||
|
||||
default:
|
||||
// no computed edge means standard rounded rect
|
||||
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
//Draw it
|
||||
CGContextStrokePath(context);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = YES;
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
_mouseDownPressed = NO;
|
||||
[super mouseUp:anEvent];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* CPCibRuntimeAttributesConnector.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Aparajita Fishman.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPCibConnector.j"
|
||||
|
||||
var CPCibRuntimeAttributesConnectorObjectKey = @"CPCibRuntimeAttributesConnectorObjectKey",
|
||||
CPCibRuntimeAttributesConnectorKeyPathsKey = @"CPCibRuntimeAttributesConnectorKeyPathsKey",
|
||||
CPCibRuntimeAttributesConnectorValuesKey = @"CPCibRuntimeAttributesConnectorValuesKey";
|
||||
|
||||
@implementation CPCibRuntimeAttributesConnector : CPCibConnector
|
||||
{
|
||||
id _keyPaths;
|
||||
id _values;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_source = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
_keyPaths = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
_values = [aCoder decodeObjectForKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_source forKey:CPCibRuntimeAttributesConnectorObjectKey];
|
||||
[aCoder encodeObject:_keyPaths forKey:CPCibRuntimeAttributesConnectorKeyPathsKey];
|
||||
[aCoder encodeObject:_values forKey:CPCibRuntimeAttributesConnectorValuesKey];
|
||||
}
|
||||
|
||||
- (void)establishConnection
|
||||
{
|
||||
var count = [_keyPaths count];
|
||||
|
||||
while (count--)
|
||||
[_source setValue:_values[count] forKeyPath:_keyPaths[count]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -61,14 +61,14 @@ var _CPCibClassSwapperClassNameKey = @"_CPCibClassSwapperClassNameKey",
|
||||
|
||||
if (!object)
|
||||
{
|
||||
CPLog.error("Unable to find class " + theClassName + " referenced in cib file.");
|
||||
CPLog.error("Unable to find class " + theClassName + " in cib file.");
|
||||
|
||||
object = [self allocObjectWithCoder:aCoder className:[aCoder decodeObjectForKey:_CPCibClassSwapperOriginalClassNameKey]];
|
||||
}
|
||||
}
|
||||
|
||||
if (!object)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " referenced in cib file."];
|
||||
[CPException raise:CPInvalidArgumentException reason:@"Unable to find class " + theClassName + " in cib file."];
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -43,11 +43,6 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObject:aSize forKey:@"size"]];
|
||||
}
|
||||
|
||||
+ (id)imageResourceWithName:(CPString)aResourceName size:(CGSize)aSize bundleClass:(CPString)aBundleClass
|
||||
{
|
||||
return [[self alloc] initWithClassName:@"CPImage" resourceName:aResourceName properties:[CPDictionary dictionaryWithObjects:[aSize, aBundleClass] forKeys:[@"size", @"bundleClass"]]];
|
||||
}
|
||||
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
self = [super init];
|
||||
@@ -94,18 +89,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
else if (_resourceName == "CPRemoveTemplate")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
|
||||
var bundleClass = _properties.valueForKey(@"bundleClass"),
|
||||
bundle = nil;
|
||||
|
||||
if (bundleClass)
|
||||
{
|
||||
bundleClass = CPClassFromString(bundleClass);
|
||||
|
||||
if (bundleClass)
|
||||
bundle = [CPBundle bundleForClass:bundleClass];
|
||||
}
|
||||
|
||||
return [[CPImage alloc] initWithContentsOfFile:[(bundle || [aCoder bundle]) pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
@import "CPCibControlConnector.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPCibBindingConnector.j"
|
||||
@import "CPCibRuntimeAttributesConnector.j"
|
||||
|
||||
|
||||
@implementation _CPCibObjectData : CPObject
|
||||
@@ -258,29 +257,11 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
|
||||
_replacementObjects[[_fileOwner UID]] = anOwner;
|
||||
|
||||
var index = 0,
|
||||
count = _connections.length,
|
||||
runtimeAttributeConnectors = [],
|
||||
connection = nil;
|
||||
count = _connections.length;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
connection = _connections[index];
|
||||
|
||||
if ([connection isKindOfClass:[CPCibRuntimeAttributesConnector class]])
|
||||
// Defer runtime attribute connections until after all other connections are made
|
||||
runtimeAttributeConnectors.push(connection);
|
||||
else
|
||||
{
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
}
|
||||
}
|
||||
|
||||
count = runtimeAttributeConnectors.length;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
connection = runtimeAttributeConnectors[index];
|
||||
var connection = _connections[index];
|
||||
|
||||
[connection replaceObjects:_replacementObjects];
|
||||
[connection establishConnection];
|
||||
|
||||
@@ -267,32 +267,6 @@ function CGPointFromEvent(anEvent)
|
||||
return _CGPointMake(anEvent.clientX, anEvent.clientY);
|
||||
}
|
||||
|
||||
/*!
|
||||
Combines two insets by adding their individual elements and returns the result.
|
||||
|
||||
@group CGInset
|
||||
*/
|
||||
function CGInsetUnion(lhsInset, rhsInset)
|
||||
{
|
||||
return _CGInsetMake(lhsInset.top + rhsInset.top,
|
||||
lhsInset.right + rhsInset.right,
|
||||
lhsInset.bottom + rhsInset.bottom,
|
||||
lhsInset.left + rhsInset.left);
|
||||
}
|
||||
|
||||
/*!
|
||||
Subtract one inset from another by subtracting their individual elements and returns the result.
|
||||
|
||||
@group CGInset
|
||||
*/
|
||||
function CGInsetDifference(lhsInset, rhsInset)
|
||||
{
|
||||
return _CGInsetMake(lhsInset.top - rhsInset.top,
|
||||
lhsInset.right - rhsInset.right,
|
||||
lhsInset.bottom - rhsInset.bottom,
|
||||
lhsInset.left - rhsInset.left);
|
||||
}
|
||||
|
||||
function CGInsetFromString(aString)
|
||||
{
|
||||
var numbers = aString.substr(1, aString.length - 2).split(',');
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* CGContextText.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
kCGTextFill = 0;
|
||||
kCGTextStroke = 1;
|
||||
kCGTextFillStroke = 2;
|
||||
kCGTextInvisible = 3;
|
||||
|
||||
function CGContextGetTextMatrix(/* CGContext */ aContext)
|
||||
{
|
||||
return aContext._textMatrix;
|
||||
}
|
||||
|
||||
function CGContextSetTextMatrix(/* CGContext */ aContext, /* CGAffineTransform */ aTransform)
|
||||
{
|
||||
aContext._textMatrix = aTransform;
|
||||
}
|
||||
|
||||
function CGContextGetTextPosition(/* CGContext */ aContext)
|
||||
{
|
||||
return aContext._textPosition || _CGPointMakeZero();
|
||||
}
|
||||
|
||||
function CGContextSetTextPosition(/* CGContext */ aContext, /* float */ x, /* float */ y)
|
||||
{
|
||||
aContext._textPosition = CGPointMake(x, y);
|
||||
}
|
||||
|
||||
function CGContextGetFont(/* CGContext */ aContext)
|
||||
{
|
||||
return aContext._CPFont;
|
||||
}
|
||||
|
||||
function CGContextSelectFont(/* CGContext */ aContext, /* CPFont */ aFont)
|
||||
{
|
||||
aContext.font = [aFont cssString];
|
||||
aContext._CPFont = aFont;
|
||||
}
|
||||
|
||||
function CGContextSetTextDrawingMode(/* CGContext */ aContext, /* CGTextDrawingMode */ aMode)
|
||||
{
|
||||
aContext._textDrawingMode = aMode;
|
||||
}
|
||||
|
||||
function CGContextShowText(/* CGContext */ aContext, /* CPString */ aString)
|
||||
{
|
||||
CGContextShowTextAtPoint(aContext, aContext._textPosition.x, aContext._textPosition.y, aString);
|
||||
}
|
||||
|
||||
function CGContextShowTextAtPoint(/* CGContext */ aContext, /* float */ x, /* float */ y, /* CPString */ aString)
|
||||
{
|
||||
aContext.textBaseline = @"middle";
|
||||
aContext.textAlign = @"left";
|
||||
|
||||
var mode = aContext._textDrawingMode;
|
||||
if (!mode && mode !== 0)
|
||||
mode = kCGTextFill;
|
||||
|
||||
var width = aContext.measureText(aString).width;
|
||||
|
||||
if (mode === kCGTextFill || mode === kCGTextFillStroke)
|
||||
aContext.fillText(aString, x, y);
|
||||
if (mode === kCGTextStroke || mode === kCGTextFillStroke)
|
||||
aContext.strokeText(aString, x, y);
|
||||
|
||||
aContext._textPosition = CGPointMake(x + width, y);
|
||||
}
|
||||
|
||||
// FIXME: these are hacks that override the default behavior.
|
||||
|
||||
function CGContextSetFillColor(/* CGContext */ aContext, /* CPColor */ aColor)
|
||||
{
|
||||
aContext.fillStyle = [aColor cssString];
|
||||
aContext._CPColor = aColor;
|
||||
}
|
||||
|
||||
function CGContextGetFillColor(/* CGContext */ aContext)
|
||||
{
|
||||
return aContext._CPColor;
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* CTFrame.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CTLine.j"
|
||||
|
||||
|
||||
kCTFrameProgressionTopToBottom = 0;
|
||||
kCTFrameProgressionRightToLeft = 1;
|
||||
|
||||
kCTFrameProgressionAttributeName = @"kCTFrameProgressionAttributeName";
|
||||
|
||||
function _CTFrameCreate(aPath, attributes, lines, attributedString)
|
||||
{
|
||||
return {
|
||||
path: aPath,
|
||||
attributes: attributes,
|
||||
lines: lines,
|
||||
string: attributedString
|
||||
};
|
||||
}
|
||||
|
||||
_CTFrameCreate.displayName = @"_CTFrameCreate";
|
||||
|
||||
/*!
|
||||
Returns the range of the frame based on the original string
|
||||
FIX ME: This implementation is wrong
|
||||
*/
|
||||
function CTFrameGetStringRange(/* CTFrame */ aFrame)
|
||||
{
|
||||
return CPMakeRange();
|
||||
}
|
||||
|
||||
CTFrameGetStringRange.displayName = @"CTFrameGetStringRange";
|
||||
|
||||
/*!
|
||||
Returns a range object with the visisble characters
|
||||
FIX ME: THis implementation is wrong
|
||||
*/
|
||||
function CTFrameGetVisibleStringRange(/* CTFrame */ aFrame)
|
||||
{
|
||||
return CPMakeRange();
|
||||
}
|
||||
|
||||
CTFrameGetVisibleStringRange.displayName = @"CTFrameGetVisibleStringRange";
|
||||
|
||||
/*!
|
||||
Returns the path for the frame.
|
||||
*/
|
||||
function CTFrameGetPath(/* CTFrame */ aFrame)
|
||||
{
|
||||
return aFrame.path;
|
||||
}
|
||||
|
||||
CTFrameGetPath.displayName = @"CTFrameGetPath";
|
||||
|
||||
/*!
|
||||
Returns a dictionary of attributes for the frame.
|
||||
*/
|
||||
function CTFrameGetFrameAttributes(/* CTFrame */ aFrame)
|
||||
{
|
||||
return aFrame.frameAttributes;
|
||||
}
|
||||
|
||||
CTFrameGetFrameAttributes.displayName = @"CTFrameGetFrameAttributes";
|
||||
|
||||
/*!
|
||||
Returns the array containing CTLines that make up the frame
|
||||
*/
|
||||
function CTFrameGetLines(/* CTFrame */ aFrame)
|
||||
{
|
||||
return aFrame.lines;
|
||||
}
|
||||
|
||||
CTFrameGetLines.displayName = @"CTFrameGetLines";
|
||||
|
||||
/*!
|
||||
Returns an array of CGPoints for the origin of each CTLine in the frame
|
||||
*/
|
||||
function CTFrameGetLineOrigins(/* CTFrame */ aFrame, /* CPRange */ aRange)
|
||||
{
|
||||
var results = [],
|
||||
lines = aRange ? CTFrameGetLinesForRange(aFrame, aRange) : aFrame.lines;
|
||||
|
||||
for (var i = -1, count = lines.length; ++i < count;)
|
||||
results.push(lines[i].origin);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
CTFrameGetLineOrigins.displayName = @"CTFrameGetLineOrigins";
|
||||
|
||||
/*!
|
||||
Returns an array of CTLines for a given range.
|
||||
Divergent from Cocoa and expensive.
|
||||
*/
|
||||
function CTFrameGetLinesForRange(/* CTFrame */ aFrame, /* CPRange */ lhs)
|
||||
{
|
||||
var lines = aFrame.lines, results = [];
|
||||
for (var i = -1, count = lines.length; ++i < count;)
|
||||
{
|
||||
var line = lines[i],
|
||||
rhs = CTLineGetStringRange(line);
|
||||
|
||||
if ((CPMaxRange(lhs) < rhs.location || CPMaxRange(rhs) < lhs.location) && result.length)
|
||||
break;
|
||||
|
||||
if (lhs.location >= rhs.location && rhs.location <= CPMaxRange(lhs) && CPMaxRange(rhs) > lhs.location)
|
||||
results.push(line);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
CTFrameGetLinesForRange.displayName = @"CTFrameGetLinesForRange";
|
||||
|
||||
/*!
|
||||
Returns a CPRange
|
||||
This is divergent from Cocoa. It's a convenience method used in CPTextView.
|
||||
*/
|
||||
function CTFrameGetRangeForPoint(/* CTFrame */ aFrame, /* CGPoint */ aPoint)
|
||||
{
|
||||
var lines = aFrame.lines, y = aPoint.y;
|
||||
for (var i = -1, count = lines.length; ++i < count;)
|
||||
{
|
||||
var line = lines[i],
|
||||
bounds = CTLineGetImageBounds(line),
|
||||
lineY = line._startPosition.y;
|
||||
|
||||
if (y >= lineY && y < bounds.size.height + lineY)
|
||||
{
|
||||
// FIXME: we seem to be doing stuff like this with some frequency;
|
||||
// Maybe it should be normalized at an earlier point.
|
||||
var index = CTLineGetStringIndexForPosition(line, aPoint),
|
||||
range = CTLineGetStringRange(line);
|
||||
|
||||
range.location += index;
|
||||
range.length = 0;
|
||||
return range;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CTFrameGetRangeForPoint.displayName = @"CTFrameGetRangeForPoint";
|
||||
|
||||
/*!
|
||||
Draws the frame to the graphics context.
|
||||
*/
|
||||
function CTFrameDraw(/* CTFrame */ aFrame, /* CGContext */ aContext)
|
||||
{
|
||||
var origin = aFrame.path.start,
|
||||
lines = aFrame.lines;
|
||||
|
||||
CGContextSetTextPosition(aContext, origin.x, origin.y);
|
||||
|
||||
for (var i = -1, count = lines.length; ++i < count;)
|
||||
{
|
||||
var line = lines[i],
|
||||
alignment = [line.string attribute:@"alignment" atIndex:0 effectiveRange:CPMakeRange(0, 0)],
|
||||
position = CGContextGetTextPosition(aContext);
|
||||
|
||||
if (alignment === CPRightTextAlignment)
|
||||
line.origin = CGPointMake((aFrame.path.elements[1].x - origin.x * 2) - CTLineGetTypographicBounds(line).width, position.y);
|
||||
else if (alignment === CPCenterTextAlignment)
|
||||
line.origin = CGPointMake(((aFrame.path.elements[1].x - origin.x) / 2) - CTLineGetTypographicBounds(line).width / 2, position.y);
|
||||
else
|
||||
line.origin = CGPointMake(origin.x, position.y);
|
||||
|
||||
CGContextSetTextPosition(aContext, line.origin.x, line.origin.y);
|
||||
CTLineDraw(line, aContext);
|
||||
}
|
||||
}
|
||||
|
||||
CTFrameDraw.displayName = @"CTFrameDraw";
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* CTFramesetter.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CTFrame.j"
|
||||
@import "CTTypesetter.j"
|
||||
|
||||
|
||||
/*!
|
||||
Creates a typesetter with a given CPAttributedString
|
||||
*/
|
||||
function CTFramesetterCreateWithAttributedString(/* CPAttributedString */ aString)
|
||||
{
|
||||
return {
|
||||
string: aString,
|
||||
typesetter: CTTypesetterCreateWithAttributedString(aString)
|
||||
};
|
||||
}
|
||||
|
||||
CTFramesetterCreateWithAttributedString.displayName = @"CTFramesetterCreateWithAttributedString";
|
||||
|
||||
/*!
|
||||
Creates a CTFrame with a given typesetter, range, path, and attributes
|
||||
*/
|
||||
function CTFramesetterCreateFrame(/* CTFramesetter */ aFramesetter, /* CPRange */ aRange, /* CGPath */ aPath, /* CPDictionary */ frameAttributes)
|
||||
{
|
||||
if (aFramesetter._cachedFrame && [aFramesetter._cachedAttributes isEqual:frameAttributes])
|
||||
return aFramesetter._cachedFrame;
|
||||
|
||||
var attributedString = aRange ? [aFramesetter.string attributedSubstringFromRange:aRange] : aFramesetter.string,
|
||||
nonattributedString = [attributedString string],
|
||||
splitLines = nonattributedString.split(/\n|\r/g),
|
||||
lines = [];
|
||||
|
||||
var index = 0;
|
||||
for (var i = -1, count = splitLines.length; ++i < count;)
|
||||
{
|
||||
var length = splitLines[i].length;
|
||||
if (i !== count - 1)
|
||||
++length;
|
||||
|
||||
var range = CPMakeRange(index, length),
|
||||
line = CTLineCreateWithAttributedString([attributedString attributedSubstringFromRange:range]);
|
||||
|
||||
line.range = range; // FIXME: a couple hacks to make managing lines in CPTextView easier
|
||||
line.prevLine = lastLine;
|
||||
|
||||
if (lastLine)
|
||||
lastLine.nextLine = line;
|
||||
|
||||
lines.push(line);
|
||||
index += length;
|
||||
|
||||
var lastLine = line;
|
||||
}
|
||||
|
||||
return aFramesetter._cachedFrame = _CTFrameCreate(aPath, frameAttributes, lines);
|
||||
}
|
||||
|
||||
CTFramesetterCreateFrame.displayName = @"CTFramesetterCreateFrame";
|
||||
|
||||
/*!
|
||||
Returns a CTTypesetter
|
||||
*/
|
||||
function CTFramesetterGetTypesetter(/* CTFramesetter */ aFramesetter)
|
||||
{
|
||||
return aFramesetter.typesetter;
|
||||
}
|
||||
|
||||
CTFramesetterGetTypesetter.displayName = @"CTFramesetterGetTypesetter";
|
||||
|
||||
/*!
|
||||
Returns a CGSize object with the suggested size for a given frame.
|
||||
*/
|
||||
function CTFramesetterSuggestFrameSizeWithConstraints(/* CTFramesetter */ aFramesetter, /* CPRange */ aRange, /* CPDictionary */ frameAttributes, /* CGSize */ constraints, /* {CPRange} */ fitRange)
|
||||
{
|
||||
var frame = CTFramesetterCreateFrame(aFramesetter, aRange, null, frameAttributes),
|
||||
lines = CTFrameGetLines(frame),
|
||||
width = 0.0,
|
||||
height = 0.0;
|
||||
|
||||
for (var i = -1, count = lines.length; ++i < count;)
|
||||
{
|
||||
var bounds = CTLineGetTypographicBounds(lines[i]);
|
||||
// var bounds = CTLineGetImageBounds(lines[i], [[CPGraphicsContext currentContext] graphicsPort]).size;
|
||||
width = MAX(width, bounds.width);
|
||||
height += bounds.lineHeight;
|
||||
// height += bounds.height;
|
||||
}
|
||||
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
CTFramesetterSuggestFrameSizeWithConstraints.displayName = @"CTFramesetterSuggestFrameSizeWithConstraints";
|
||||
|
||||
/*!
|
||||
Returns the CPAttributedString for a given framesetter
|
||||
*/
|
||||
function CTFramesetterGetAttributedString(/* CTFramesetter */ aFramesetter)
|
||||
{
|
||||
return aFramesetter.string;
|
||||
}
|
||||
|
||||
CTFramesetterGetAttributedString.displayName = @"CTFramesetterGetAttributedString";
|
||||
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* CTLine.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CTRun.j"
|
||||
|
||||
|
||||
kCTLineTruncationStart = 0;
|
||||
kCTLineTruncationEnd = 1;
|
||||
kCTLineTruncationMiddle = 2;
|
||||
|
||||
/*!
|
||||
Creates a new line with a supplied CPAttributedString
|
||||
*/
|
||||
function CTLineCreateWithAttributedString(/* CPAttributedString */ aString)
|
||||
{
|
||||
var line = {
|
||||
string: aString,
|
||||
runs: []
|
||||
};
|
||||
|
||||
_CTLineCreateRuns(line);
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
CTLineCreateWithAttributedString.displayName = @"CTLineCreateWithAttributedString";
|
||||
|
||||
/*!
|
||||
Creates a new line truncated to a given width.
|
||||
@param aLine - The input line
|
||||
@param width - The constraining width
|
||||
@param truncationToken - The characters to represent the truncation. This is usually an elipsis. If not token is given the string will just clip
|
||||
|
||||
FIX ME: Not implemented correctly
|
||||
*/
|
||||
function CTLineCreateTruncatedLine(/* CTLine */ aLine, /* float */ width, /* CTLineTruncationType */ truncationType, /* CTLine */ truncationToken)
|
||||
{
|
||||
return aLine;
|
||||
}
|
||||
|
||||
CTLineCreateTruncatedLine.displayName = @"CTLineCreateTruncatedLine";
|
||||
|
||||
/*!
|
||||
Returns a CTLine with justified text.
|
||||
FIX ME: This is not implemented correctly
|
||||
*/
|
||||
function CTLineCreateJustifiedLine(/* CTline */ aLine, /* float */ justificationFactor, /* float */ width)
|
||||
{
|
||||
return aLine;
|
||||
}
|
||||
|
||||
CTLineCreateJustifiedLine.displayName = @"CTLineCreateJustifiedLine";
|
||||
|
||||
/*!
|
||||
Returns the number of glyphs in a given line.
|
||||
*/
|
||||
function CTLineGetGlyphCount(/* CTLine */ aLine)
|
||||
{
|
||||
return [aLine.string length];
|
||||
}
|
||||
|
||||
CTLineGetGlyphCount.displayName = @"CTLineGetGlyphCount";
|
||||
|
||||
/*!
|
||||
Returns the array of CTRuns that make up the line.
|
||||
*/
|
||||
function CTLineGetGlyphRuns(/* CTLine */ aLine)
|
||||
{
|
||||
return aLine.runs;
|
||||
}
|
||||
|
||||
CTLineGetGlyphRuns.displayName = @"CTLineGetGlyphRuns";
|
||||
|
||||
/*!
|
||||
Returns the range for which the CTLine makes up the original string
|
||||
*/
|
||||
function CTLineGetStringRange(/* CTLine */ aLine)
|
||||
{
|
||||
return CPCopyRange(aLine.range) || CPMakeRange(0, [aLine.string length])
|
||||
}
|
||||
|
||||
CTLineGetStringRange.displayName = @"CTLineGetStringRange";
|
||||
|
||||
/*!
|
||||
No op
|
||||
*/
|
||||
function CTLineGetPenOffsetForFlush(/* CTLine */ aLine, /* float */ flushFactor, /* float */ flushWidth)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CTLineGetPenOffsetForFlush.displayName = @"CTLineGetPenOffsetForFlush";
|
||||
/*!
|
||||
Draws the CTLine to the graphics context.
|
||||
*/
|
||||
function CTLineDraw(/* CTLine */ aLine, /* CGContext */ aContext)
|
||||
{
|
||||
var startPosition = aLine._startPosition = CGContextGetTextPosition(aContext),
|
||||
height = CTLineGetImageBounds(aLine, aContext).size.height;
|
||||
|
||||
// FIXME: This is WRONG. This NEEDS to be in CGContext.
|
||||
CGContextSetTextPosition(aContext, startPosition.x, startPosition.y + height * 0.5);
|
||||
|
||||
var runs = aLine.runs;
|
||||
for (var i = -1, count = runs.length; ++i < count;)
|
||||
CTRunDraw(runs[i], aContext);
|
||||
|
||||
CGContextSetTextPosition(aContext, startPosition.x, startPosition.y + height);
|
||||
}
|
||||
|
||||
CTLineDraw.displayName = @"CTLineDraw";
|
||||
|
||||
/*!
|
||||
Calcaulates the image bounds for a line.
|
||||
*/
|
||||
function CTLineGetImageBounds(/* CTLine */ aLine, /* CGContext */ aContext)
|
||||
{
|
||||
if (aLine._imageBounds)
|
||||
return aLine._imageBounds;
|
||||
|
||||
var runs = aLine.runs,
|
||||
width = 0.0,
|
||||
height = 0.0;
|
||||
|
||||
for (var i = -1, count = runs.length; ++i < count;)
|
||||
{
|
||||
var runSize = CTRunGetImageBounds(runs[i], aContext).size;
|
||||
width += runSize.width;
|
||||
height = MAX(height, runSize.height);
|
||||
}
|
||||
|
||||
return aLine._imageBounds = CGRectMake(0.0, 0.0, width, height);
|
||||
}
|
||||
|
||||
CTLineGetImageBounds.displayName = @"CTLineGetImageBounds";
|
||||
|
||||
/*!
|
||||
Returns a JSObject: {width: float, ascent: float, descent: float, lineHeight: float}
|
||||
This method is more expensive than CTLineGetImageBounds.
|
||||
*/
|
||||
function CTLineGetTypographicBounds(/* CTLine */ aLine)
|
||||
{
|
||||
if (aLine._typographicBounds)
|
||||
return aLine._typographicBounds;
|
||||
|
||||
var runs = aLine.runs,
|
||||
width = 0.0,
|
||||
ascent = 0.0,
|
||||
descent = 0.0,
|
||||
lineHeight = 0.0;
|
||||
|
||||
for (var i = -1, count = runs.length; ++i < count;)
|
||||
{
|
||||
var runObject = CTRunGetTypographicBounds(runs[i]);
|
||||
width += runObject.width;
|
||||
ascent = MAX(ascent, runObject.ascent);
|
||||
descent = MAX(descent, runObject.descent);
|
||||
lineHeight = MAX(lineHeight, runObject.lineHeight);
|
||||
}
|
||||
|
||||
return aLine._typographicBounds = {
|
||||
width: width,
|
||||
ascent: ascent,
|
||||
descent: descent,
|
||||
lineHeight: lineHeight
|
||||
};
|
||||
}
|
||||
|
||||
CTLineGetTypographicBounds.displayName = @"CTLineGetTypographicBounds";
|
||||
|
||||
/*!
|
||||
Returns the index of the line based on the original string
|
||||
*/
|
||||
function CTLineGetStringIndexForPosition(/* CTLine */ aLine, /* CGPoint */ aPoint)
|
||||
{
|
||||
var runs = aLine.runs, x = aPoint.x, index = 0;
|
||||
for (var i = -1, count = runs.length; ++i < count;)
|
||||
{
|
||||
var run = runs[i],
|
||||
origins = run.glyphOrigins;
|
||||
|
||||
for (var j = -1, jcount = origins.length; ++j < jcount;)
|
||||
{
|
||||
var origin = origins[j], next;
|
||||
if (j < jcount - 1)
|
||||
next = origins[j + 1];
|
||||
else if (i < count - 1)
|
||||
next = runs[i + 1].glyphOrigins[0];
|
||||
else
|
||||
return index++;
|
||||
|
||||
if (x <= (next.x - origin.x) / 2 + origin.x)
|
||||
return index;
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CTLineGetStringIndexForPosition.displayName = @"CTLineGetStringIndexForPosition";
|
||||
|
||||
/*!
|
||||
Returns the offset corresponding to a string index,
|
||||
this works well for for movement between adjacent lines or for drawing a custom caret.
|
||||
*/
|
||||
function CTLineGetOffsetForStringIndex(/* CTLine */ aLine, /* int */ anIndex, /* float */ secondaryOffset)
|
||||
{
|
||||
var runs = aLine.runs;
|
||||
for (var i = -1, count = runs.length; ++i < count;)
|
||||
{
|
||||
var run = runs[i], runRange = run.range;
|
||||
if (CPLocationInRange(anIndex, runRange))
|
||||
return run.glyphOrigins[anIndex - runRange.location];
|
||||
}
|
||||
}
|
||||
|
||||
CTLineGetOffsetForStringIndex.displayName = @"CTLineGetOffsetForStringIndex";
|
||||
|
||||
function _CTLineCreateRuns(aLine)
|
||||
{
|
||||
var string = aLine.string,
|
||||
runs = aLine.runs,
|
||||
rangeEntries = string._rangeEntries;
|
||||
|
||||
for (var i = -1, count = rangeEntries.length; ++i < count;)
|
||||
{
|
||||
var rangeEntry = rangeEntries[i],
|
||||
range = rangeEntry.range,
|
||||
rangeString = [[string string] substringWithRange:range],
|
||||
attributes = rangeEntry.attributes;
|
||||
|
||||
var run = _CTRunCreate(rangeString, attributes);
|
||||
run.range = range;
|
||||
|
||||
runs.push(run);
|
||||
}
|
||||
}
|
||||
|
||||
_CTLineCreateRuns.displayName = @"_CTLineCreateRuns";
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* CTRun.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
kCTRunStatusNoStatus = 0;
|
||||
kCTRunStatusRightToLeft = 1 << 0;
|
||||
kCTRunStatusNonMonotonic = 1 << 1;
|
||||
kCTRunStatusNonIdentityMatrix = 1 << 2;
|
||||
|
||||
/*!
|
||||
A CTRun represents a span of characters with common attribtues.
|
||||
*/
|
||||
|
||||
function _CTRunCreate(glyphs, attributes)
|
||||
{
|
||||
return {
|
||||
glyphs: glyphs,
|
||||
attributes: attributes,
|
||||
status: kCTRunStatusNoStatus
|
||||
};
|
||||
}
|
||||
|
||||
_CTRunCreate.displayName = @"_CTRunCreate";
|
||||
|
||||
/*!
|
||||
Returns the number of glyphs in the run.
|
||||
*/
|
||||
function CTRunGetGlyphCount(/* CTRun */ aRun)
|
||||
{
|
||||
return aRun.glyphs.length;
|
||||
}
|
||||
|
||||
CTRunGetGlyphCount.displayName = @"CTRunGetGlyphCount";
|
||||
|
||||
/*!
|
||||
Returns a CPDictionary of attributes for the CTRun
|
||||
*/
|
||||
function CTRunGetAttributes(/* CTRun */ aRun)
|
||||
{
|
||||
return aRun.attributes;
|
||||
}
|
||||
|
||||
CTRunGetAttributes.displayName = @"CTRunGetAttributes";
|
||||
|
||||
/*!
|
||||
Returns a CTRunStatus
|
||||
CTRuns have status that can be used to speed up certain operations.
|
||||
|
||||
Possible values:
|
||||
|
||||
@code
|
||||
kCTRunStatusNoStatus
|
||||
kCTRunStatusRightToLeft
|
||||
kCTRunStatusNonMonotonic
|
||||
kCTRunStatusNonIdentityMatrix
|
||||
@endcode
|
||||
*/
|
||||
function CTRunGetStatus(/* CTRun */ aRun)
|
||||
{
|
||||
return aRun.status || kCTRunStatusNoStatus;
|
||||
}
|
||||
|
||||
CTRunGetStatus.displayName = @"CTRunGetStatus";
|
||||
|
||||
/*!
|
||||
Returns an array of CGGlyphs
|
||||
FIX ME: Not implemented correctly
|
||||
*/
|
||||
function CTRunGetGlyphs(/* CTRun */ aRun, /* CPRange */ aRange)
|
||||
{
|
||||
if (!aRun.glyphs)
|
||||
aRun.glyphs = [];
|
||||
|
||||
return aRun.glyphs;
|
||||
}
|
||||
|
||||
CTRunGetGlyphs.displayName = @"CTRunGetGlyphs";
|
||||
|
||||
/*!
|
||||
Returns an array of CGPoints
|
||||
FIX ME: Not implemented correctly
|
||||
*/
|
||||
function CTRunGetPositions(/* CTRun */ aRun, /* CPRange */ aRange)
|
||||
{
|
||||
if (!aRun.positions)
|
||||
aRun.positions = [];
|
||||
|
||||
return aRun.positions;
|
||||
}
|
||||
|
||||
CTRunGetPositions.displayName = @"CTRunGetPositions";
|
||||
|
||||
/*!
|
||||
Returns an array of CGSizes
|
||||
FIX ME: Not implemented correctly
|
||||
*/
|
||||
function CTRunGetAdvances(/* CTRun */ aRun, /* CPRange */ aRange)
|
||||
{
|
||||
if (!aRun.advances)
|
||||
aRun.advances = [];
|
||||
|
||||
return aRun.advances;
|
||||
}
|
||||
|
||||
CTRunGetAdvances.displayName = @"CTRunGetAdvances";
|
||||
|
||||
/*!
|
||||
Returns an array of indexes.
|
||||
FIX ME: Not implemented correctly
|
||||
*/
|
||||
function CTRunGetStringIndices(/* CTRun */ aRun, /* CPRange */ aRange)
|
||||
{
|
||||
if (!aRun.stringIndices)
|
||||
aRun.stringIndices = [];
|
||||
|
||||
return aRun.stringIndices;
|
||||
}
|
||||
|
||||
CTRunGetStringIndices.displayName = @"CTRunGetStringIndices";
|
||||
|
||||
/*!
|
||||
Returns a CPRange containing the location of the run in the parent string
|
||||
*/
|
||||
function CTRunGetStringRange(/* CTRun */ aRun)
|
||||
{
|
||||
return aRun.range;
|
||||
}
|
||||
|
||||
CTRunGetStringRange.displayName = @"CTRunGetStringRange";
|
||||
|
||||
/*!
|
||||
Returns a JSObject: {width: float, ascender: float, descender: float, lineHeight: float}
|
||||
More expensive
|
||||
*/
|
||||
function CTRunGetTypographicBounds(/* CTRun */ aRun, /* CPRange */ aRange)
|
||||
{
|
||||
if (aRun._typographicBounds)
|
||||
return aRun._typographicBounds;
|
||||
|
||||
var attributes = aRun.attributes,
|
||||
font = [attributes valueForKey:@"font"],
|
||||
string = _CTRunStringForRange(aRun, aRange);
|
||||
|
||||
return aRun._typographicBounds = {
|
||||
width: [string sizeWithFont:font].width, // FIXME: account for tabs
|
||||
ascender: [font ascender],
|
||||
descender: [font descender],
|
||||
lineHeight: [font defaultLineHeightForFont]
|
||||
};
|
||||
}
|
||||
|
||||
CTRunGetTypographicBounds.displayName = @"CTRunGetTypographicBounds";
|
||||
|
||||
/*!
|
||||
Returns a CGRect
|
||||
Cheap
|
||||
*/
|
||||
function CTRunGetImageBounds(/* CTRun */ aRun, /* CGContext */ aContext, /* CPRange */ aRange)
|
||||
{
|
||||
if (aRun._imageBounds)
|
||||
return aRun._imageBounds;
|
||||
|
||||
_CTRunPrepareDraw(aRun, aContext);
|
||||
|
||||
var string = _CTRunStringForRange(aRun, aRange),
|
||||
width = aContext.measureText(string).width,
|
||||
height = [CGContextGetFont(aContext) defaultLineHeightForFont];
|
||||
|
||||
_CTRunUnprepareDraw(aRun, aContext);
|
||||
|
||||
return aRun._imageBounds = CGRectMake(0.0, 0.0, width, height);
|
||||
}
|
||||
|
||||
CTRunGetImageBounds.displayName = @"CTRunGetImageBounds";
|
||||
|
||||
// CGAffineTransform
|
||||
function CTRunGetTextMatrix(/* CTRun */ aRun)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CTRunGetTextMatrix.displayName = @"CTRunGetTextMatrix";
|
||||
|
||||
/*!
|
||||
Draws the run to the context
|
||||
*/
|
||||
function CTRunDraw(/* CTRun */ aRun, /* CGContext */ aContext, /* CPRange */ aRange)
|
||||
{
|
||||
_CTRunPrepareDraw(aRun, aContext);
|
||||
|
||||
var string = aRange ? [aRun.glyphs substringWithRange:aRange] : aRun.glyphs;
|
||||
_CTRunDrawShadow(aRun, aContext, string);
|
||||
|
||||
var origins = aRun.glyphOrigins = [];
|
||||
for (var i = -1, count = string.length; ++i < count;)
|
||||
{
|
||||
var glyph = string[i];
|
||||
origins[i] = CGContextGetTextPosition(aContext);
|
||||
|
||||
CGContextShowText(aContext, glyph);
|
||||
}
|
||||
|
||||
_CTRunUnprepareDraw(aRun, aContext);
|
||||
}
|
||||
|
||||
CTRunDraw.displayName = @"CTRunDraw";
|
||||
|
||||
function _CTRunDrawShadow(aRun, aContext, aString)
|
||||
{
|
||||
var attributes = aRun.attributes,
|
||||
textShadowColor = [attributes valueForKey:@"text-shadow-color"],
|
||||
textShadowOffset = [attributes valueForKey:@"text-shadow-offset"];
|
||||
|
||||
if (textShadowColor && textShadowOffset)
|
||||
{
|
||||
var color = CGContextGetFillColor(aContext),
|
||||
position = CGContextGetTextPosition(aContext);
|
||||
|
||||
CGContextSetFillColor(aContext, textShadowColor);
|
||||
CGContextShowTextAtPoint(aContext, position.x + textShadowOffset.width, position.y + textShadowOffset.height, aString);
|
||||
|
||||
CGContextSetFillColor(aContext, color);
|
||||
CGContextSetTextPosition(aContext, position.x, position.y);
|
||||
}
|
||||
}
|
||||
|
||||
_CTRunDrawShadow.displayName = @"_CTRunDrawShadow";
|
||||
|
||||
function _CTRunPrepareDraw(aRun, aContext)
|
||||
{
|
||||
var attributes = aRun.attributes,
|
||||
font = [attributes valueForKey:@"font"],
|
||||
color = [attributes valueForKey:@"color"];
|
||||
|
||||
if (font)
|
||||
{
|
||||
CGContextSelectFont(aContext, font);
|
||||
aRun._cachedFont = CGContextGetFont(aContext);
|
||||
}
|
||||
|
||||
if (color)
|
||||
{
|
||||
CGContextSetFillColor(aContext, color);
|
||||
aRun._cachedColor = CGContextGetFillColor(aContext);
|
||||
}
|
||||
}
|
||||
|
||||
_CTRunPrepareDraw.displayName = @"_CTRunPrepareDraw";
|
||||
|
||||
function _CTRunUnprepareDraw(aRun, aContext)
|
||||
{
|
||||
if (aRun._cachedFont)
|
||||
{
|
||||
CGContextSelectFont(aContext, aRun._cachedFont);
|
||||
aRun._cachedFont = nil;
|
||||
}
|
||||
|
||||
if (aRun._cachedColor)
|
||||
{
|
||||
CGContextSetFillColor(aContext, aRun._cachedColor);
|
||||
aRun._cachedColor = nil;
|
||||
}
|
||||
}
|
||||
|
||||
_CTRunUnprepareDraw.displayName = @"_CTRunUnprepareDraw";
|
||||
|
||||
function _CTRunStringForRange(aRun, aRange)
|
||||
{
|
||||
return (!aRange || aRange.length === 0) ? aRun.glyphs : [aRun.glyphs substringWithRange:aRange];
|
||||
}
|
||||
|
||||
_CTRunStringForRange.displayName = @"_CTRunStringForRange";
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* CTTypesetter.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CTLine.j"
|
||||
|
||||
|
||||
kCTTypesetterOptionDisableBidiProcessing = @"kCTTypesetterOptionDisableBidiProcessing";
|
||||
kCTTypesetterOptionForcedEmbeddingLevel = @"kCTTypesetterOptionForcedEmbeddingLevel";
|
||||
|
||||
// Returns a CTTypesetter
|
||||
function CTTypesetterCreateWithAttributedString(/* CPAttributedString */ aString)
|
||||
{
|
||||
return CTTypesetterCreateWithAttributedStringAndOptions(aString, nil);
|
||||
}
|
||||
|
||||
// Returns a CTTypesetter
|
||||
function CTTypesetterCreateWithAttributedStringAndOptions(/* CPAttributedString */ aString, /* CPDictionary */ aDictionary)
|
||||
{
|
||||
return {
|
||||
string: aString,
|
||||
options: aDictionary
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a CTLine
|
||||
function CTTypesetterCreateLine(/* CTTypesetter */ aTypesetter, /* CPRange */ aRange)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Returns an index
|
||||
function CTTypesetterSuggestLineBreak(/* CTTypesetter */ aTypesetter, /* int */ startIndex, /* float */ width)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Returns an index
|
||||
function CTTypesetterSuggestClusterBreak(/* CTTypesetter */ aTypesetter, /* int */ startIndex, /* float */ width)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
/*
|
||||
* __filename__
|
||||
* __project.name__
|
||||
* CoreText.j
|
||||
* CoreText
|
||||
*
|
||||
* Created by __user.name__ on __project.date__.
|
||||
*
|
||||
* Copyright __project.year__, __organization.name__. All rights reserved.
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2011, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -21,4 +20,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "__project.nameasidentifier__Class.j"
|
||||
@import "CTFramesetter.j"
|
||||
@import "CTFrame.j"
|
||||
@import "CTTypesetter.j"
|
||||
@import "CTLine.j"
|
||||
@import "CTRun.j"
|
||||
|
||||
@import "CGContextText.j"
|
||||
@@ -42,16 +42,7 @@
|
||||
#include "DOM/CPPlatformString.j"
|
||||
#else
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
return _CGSizeMakeZero();
|
||||
}
|
||||
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjectsAndKeys:0, @"ascender", 0, @"descender", 0, @"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,6 @@ var PrimaryPlatformWindow = NULL;
|
||||
CPInteger _level;
|
||||
BOOL _hasShadow;
|
||||
unsigned _shadowStyle;
|
||||
CPString _title;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMWindow _DOMWindow;
|
||||
@@ -259,21 +258,6 @@ var PrimaryPlatformWindow = NULL;
|
||||
return [CPPlatform isBrowser];
|
||||
}
|
||||
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
_title = aTitle;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
if (_DOMWindow && _DOMWindow.document)
|
||||
_DOMWindow.document.title = _title;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (CPString)title
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#if PLATFORM(BROWSER)
|
||||
|
||||
@@ -534,14 +534,13 @@ var ModifierKeyCodes = [
|
||||
if (_DOMWindow)
|
||||
return _DOMWindow.focus();
|
||||
|
||||
_DOMWindow = window.open("about:blank", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
_DOMWindow = window.open("", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
|
||||
|
||||
[PlatformWindows addObject:self];
|
||||
|
||||
// FIXME: cpSetFrame?
|
||||
_DOMWindow.document.write("<!DOCTYPE html><html lang='en'><head></head><body style='background-color:transparent;'></body></html>");
|
||||
_DOMWindow.document.close();
|
||||
_DOMWindow.document.title = _title;
|
||||
|
||||
if (![CPPlatform isBrowser])
|
||||
{
|
||||
|
||||
|
Before Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 361 B |
|
Before Width: | Height: | Size: 694 B |
|
Before Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 146 B |
|
Before Width: | Height: | Size: 141 B |
|
Before Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 407 B |
|
Before Width: | Height: | Size: 160 B |
|
Before Width: | Height: | Size: 348 B |
|
Before Width: | Height: | Size: 622 B |
|
Before Width: | Height: | Size: 217 B |
|
Before Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 527 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 123 B |
|
Before Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 447 B |
|
Before Width: | Height: | Size: 471 B |
|
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 149 B |
|
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 757 B |
|
Before Width: | Height: | Size: 908 B After Width: | Height: | Size: 735 B |
|
Before Width: | Height: | Size: 472 B After Width: | Height: | Size: 559 B |
|
Before Width: | Height: | Size: 515 B After Width: | Height: | Size: 531 B |
|
Before Width: | Height: | Size: 155 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 1004 B |
|
Before Width: | Height: | Size: 160 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 991 B |
|
Before Width: | Height: | Size: 115 B After Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 158 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 124 B After Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 159 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 160 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 1004 B |
|
Before Width: | Height: | Size: 164 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 117 B After Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 991 B |
|
Before Width: | Height: | Size: 115 B After Width: | Height: | Size: 994 B |
|
Before Width: | Height: | Size: 158 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 124 B After Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 159 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 133 B After Width: | Height: | Size: 1012 B |
|
Before Width: | Height: | Size: 234 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 1012 B |