Merge branch 'master' into @each

Conflicts:
	Foundation/CPArray.j
This commit is contained in:
Francisco Ryan Tolmasky I
2010-09-19 15:06:16 -07:00
385 changed files with 28701 additions and 4608 deletions
+7 -4
View File
@@ -36,8 +36,8 @@
@import "CPCibLoading.j"
@import "CPCibOutletConnector.j"
@import "CPClipView.j"
@import "CPCollectionViewItem.j"
@import "CPCollectionView.j"
@import "CPCollectionViewItem.j"
@import "CPColor.j"
@import "CPColorPanel.j"
@import "CPColorWell.j"
@@ -53,8 +53,10 @@
@import "CPFont.j"
@import "CPFontManager.j"
@import "CPGeometry.j"
@import "CPGraphics.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@@ -65,17 +67,17 @@
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
@import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@import "CPSecureTextField.j"
@import "CPSegmentedControl.j"
@import "CPShadow.j"
@import "CPSlider.j"
@import "CPSplitView.j"
@import "CPTabView.j"
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPToolbar.j"
@@ -87,3 +89,4 @@
@import "CPWebView.j"
@import "CPWindow.j"
@import "CPWindowController.j"
@import "CPArrayController.j"
+244 -95
View File
@@ -39,26 +39,21 @@
@global
@group CPAlertStyle
*/
CPWarningAlertStyle = 0;
CPWarningAlertStyle = 0;
/*
@global
@group CPAlertStyle
*/
CPInformationalAlertStyle = 1;
CPInformationalAlertStyle = 1;
/*
@global
@group CPAlertStyle
*/
CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
CPCriticalAlertStyle = 2;
/*!
@ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options.
@@ -74,41 +69,51 @@ var CPAlertWarningImage,
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
Called when the user dismisses the alert by clicking one of the buttons.
@param theAlert the alert panel that the user dismissed
@param returnCode the index of the button that the user clicked (starting from 0,
@param returnCode the index of the button that the user clicked (starting from 0,
representing the first button added to the alert which appears on the
right, 1 representing the next button to the left and so on)
*/
@implementation CPAlert : CPObject
@implementation CPAlert : CPView
{
CPPanel _alertPanel;
CPTextField _messageLabel;
CPTextField _informativeLabel;
CPImageView _alertImageView;
CPAlertStyle _alertStyle;
CPString _windowTitle;
int _windowStyle;
int _buttonCount;
CPArray _buttons;
id _delegate;
SEL _didEndSelector;
id _modalDelegate;
}
+ (void)initialize
+ (CPString)themeClass
{
if (self != CPAlert)
return;
return @"alert";
}
var bundle = [CPBundle bundleForClass:[self class]];
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
size:CGSizeMake(32.0, 32.0)];
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
size:CGSizeMake(32.0, 32.0)];
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
CGPointMake(15, 12),
[CPNull null],
[CPNull null],
[CPNull null]
]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
@"image-offset",
@"information-image",
@"warning-image",
@"error-image"
]];
}
/*!
@@ -118,57 +123,56 @@ var CPAlertWarningImage,
{
if (self = [super init])
{
_buttonCount = 0;
_buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle;
_alertPanel = nil;
_windowStyle = nil;
_didEndSelector = nil;
[self setWindowStyle:nil];
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
}
return self;
}
/*!
Sets the window appearance.
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
will be activated.
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/
- (void)setWindowStyle:(int)styleMask
{
_windowStyle = styleMask;
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
var count = [_buttons count];
for(var i=0; i < count; i++)
// We'll need to recreate the panel to get the new window style.
_alertPanel = nil;
}
- (void)_createPanel
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
var contentView = [_alertPanel contentView],
count = [_buttons count];
if (count)
{
var button = _buttons[i];
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[[_alertPanel contentView] addSubview:button];
while (count--)
[contentView addSubview:_buttons[count]];
}
if (!_messageLabel)
{
var bounds = [[_alertPanel contentView] bounds];
else
[self addButtonWithTitle:@"OK"];
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_messageLabel setAlignment:CPJustifiedTextAlignment];
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
}
[[_alertPanel contentView] addSubview:_messageLabel];
[[_alertPanel contentView] addSubview:_alertImageView];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
}
/*!
@@ -231,7 +235,7 @@ var CPAlertWarningImage,
}
/*!
Sets the receivers message text, or title, to a given text.
Sets the receivers message text, or title, to a given text.
@param messageText - Message text for the alert.
*/
- (void)setMessageText:(CPString)messageText
@@ -239,14 +243,31 @@ var CPAlertWarningImage,
[_messageLabel setStringValue:messageText];
}
/*!
Return's the receiver's message text body.
/*!
Returns the receiver's message text body.
*/
- (CPString)messageText
{
return [_messageLabel stringValue];
}
/*!
Sets the receiver's informative text, shown below the message text.
@param informativeText - The informative text.
*/
- (void)setInformativeText:(CPString)informativeText
{
[_informativeLabel setStringValue:informativeText];
}
/*!
Returns the receiver's informative text.
*/
- (CPString)informativeText
{
return [_informativeLabel stringValue];
}
/*!
Adds a button with a given title to the receiver.
Buttons will be added starting from the right hand side of the \c CPAlert panel.
@@ -260,25 +281,119 @@ var CPAlertWarningImage,
- (void)addButtonWithTitle:(CPString)title
{
var bounds = [[_alertPanel contentView] bounds],
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
_buttonCount = [_buttons count];
[button setTitle:title];
[button setTarget:self];
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[button setAction:@selector(_dismissAlert:)];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[_alertPanel setDefaultButton:button];
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([title lowercaseString] === "cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
else
[button setKeyEquivalent:nil];
_buttonCount++;
[_buttons addObject:button];
[_buttons insertObject:button atIndex:0];
}
- (void)layoutPanel
{
if (!_alertPanel)
[self _createPanel];
var inset = [self currentValueForThemeAttribute:@"content-inset"],
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theTitle,
theImage;
switch (_alertStyle)
{
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
theTitle = @"Error";
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
// FIXME sizeWithFontCorrection shouldn't be needed.
var bounds = [[_alertPanel contentView] bounds],
offsetX = CGRectGetWidth(bounds) - inset.right,
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
textWidth = offsetX - inset.left,
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
informationString = [_informativeLabel stringValue],
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
sizeWithFontCorrection = 6.0;
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
// Don't let an empty informative label partially cover the buttons.
[_informativeLabel setHidden:!informationString];
var aRepresentativeButton = _buttons[0],
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
// Make the window just tall enough to fit everything. Bit of a hack really.
var minimumSize = [self currentValueForThemeAttribute:@"size"],
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
deltaY = desiredHeight - CGRectGetHeight(bounds),
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
frameSize.height += deltaY;
[_alertPanel setFrameSize:frameSize];
var count = [_buttons count];
while (count--)
{
var button = _buttons[count];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonBounds = [button bounds],
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
height = CGRectGetHeight(buttonBounds);
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
offsetX -= 10;
}
}
/*!
@@ -288,34 +403,68 @@ var CPAlertWarningImage,
*/
- (void)runModal
{
var theTitle;
switch (_alertStyle)
{
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
theTitle = @"Error";
break;
}
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[self layoutPanel];
[CPApp runModalForWindow:_alertPanel];
}
/* @ignore */
- (void)_notifyDelegate:(id)button
{
[CPApp abortModal];
[_alertPanel close];
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:[button tag]];
@param window The parent window for the sheet.
@param modalDelegate The delegate for the modal-dialog session.
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
*/
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
_didEndSelector = alertDidEndSelector;
_modalDelegate = modalDelegate;
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
*/
- (void)beginSheetModalForWindow:(CPWindow)window
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
}
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
{
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
_didEndSelector = nil;
_modalDelegate = nil;
}
/* @ignore */
- (void)_dismissAlert:(CPButton)button
{
if ([_alertPanel isSheet])
[CPApp endSheet:_alertPanel returnCode:[button tag]];
else
{
[CPApp abortModal];
[_alertPanel close];
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
}
}
@end
+18 -5
View File
@@ -108,6 +108,8 @@ CPRunContinuesResponse = -1002;
CPImage _applicationIconImage;
CPPanel _aboutPanel;
CPThemeBlend _themeBlend @accessors(property=themeBlend);
}
/*!
@@ -325,7 +327,9 @@ CPRunContinuesResponse = -1002;
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
aboutPanelController = [CPWindowController alloc],
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1],
@@ -859,6 +863,7 @@ CPRunContinuesResponse = -1002;
}
[aWindow orderFront:self];
[aSheet setPlatformWindow:[aWindow platformWindow]];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
@@ -1016,7 +1021,6 @@ CPRunContinuesResponse = -1002;
+ (CPString)defaultThemeName
{
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
}
@@ -1032,7 +1036,8 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
return { _mask:anEventMask, _callback:aCallback };
}
var _CPRunModalLoop = function(anEvent)
// Make this a global for use in CPPlatformWindow+DOM.j.
_CPRunModalLoop = function(anEvent)
{
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -1110,8 +1115,15 @@ var _CPAppBootstrapperActions = nil;
+ (BOOL)loadDefaultTheme
{
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
var defaultThemeName = [CPApplication defaultThemeName],
themeURL = nil;
if (defaultThemeName === @"Aristo")
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
else
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
[blend loadWithDelegate:self];
return YES;
@@ -1119,6 +1131,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[self performActions];
@@ -1216,7 +1229,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)reset
{
_CPAppBootstrapperActions = nil;
_CPAppBootstrapperActions = nil;
}
@end
+229 -100
View File
@@ -58,22 +58,30 @@
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
{
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "filterPredicate", "sortDescriptors"];
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
}
+ (CPSet)keyPathsForValuesAffectingSelection
{
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes"];
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
{
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"];
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
{
// When the arranged objects change, selection preservation may cause the indexes
// to change.
return [CPSet setWithObjects:"arrangedObjects"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
{
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"];
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
@@ -91,16 +99,6 @@
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
{
if (![super automaticallyNotifiesObserversForKey:aKey])
return NO;
if (aKey === @"selectionIndexes")
return NO;
return YES;
}
- (id)init
{
self = [super init];
@@ -153,31 +151,50 @@
if(![value isKindOfClass:[CPArray class]])
value = [value];
var oldSelection = nil,
oldSelectionIndexes = [[self selectionIndexes] copy];
var oldSelectedObjects = nil,
oldSelectionIndexes = nil;
if ([self preservesSelection])
oldSelection = [self selectedObjects];
oldSelectedObjects = [self selectedObjects];
else
oldSelectionIndexes = [self selectionIndexes];
// Avoid out of bounds selections.
_selectionIndexes = [CPIndexSet indexSet];
//FIXME: copy?
[super setContent:value];
/*
When the contents are changed, the selected indexes may no longer refer to the
same items. This would cause problems when setSelectedObjects is called below.
Any KVO observation would try to retrieve the 'before' value which could be
wrong or even throw an exception for no longer existing indexes.
To avoid that, use the internal __setSelectedObjects which fires no notifications.
The selectionIndexes notifications will fire later since they depend on the
content key. This pattern is also applied for many other methods throughout this
class.
*/
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
// Don't use [super setContent:] as that would fire the contentObject change.
// We need to be in control of when notifications fire.
_contentObject = value;
if(_clearsFilterPredicateOnInsertion)
[self setFilterPredicate:nil];
[self rearrangeObjects];
if (oldSelection)
[self setSelectedObjects:oldSelection];
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self setSelectionIndexes:oldSelectionIndexes];
[self _rearrangeObjects];
if ([self preservesSelection])
[self __setSelectedObjects:oldSelectedObjects];
else
[self __setSelectionIndexes:oldSelectionIndexes];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
[self setContent:anArray];
}
- (void)_setContentSet:(id)aSet
@@ -197,42 +214,57 @@
- (CPArray)arrangeObjects:(CPArray)objects
{
var sortedObjects = objects;
var filterPredicate = [self filterPredicate],
sortDescriptors = [self sortDescriptors];
if ([self filterPredicate])
sortedObjects = [sortedObjects filteredArrayUsingPredicate:[self filterPredicate]];
if ([self sortDescriptors])
sortedObjects = [sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]];
if (filterPredicate && sortDescriptors)
{
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
[sortedObjects sortUsingDescriptors:sortDescriptors];
return sortedObjects;
}
else if (filterPredicate)
return [objects filteredArrayUsingPredicate:filterPredicate];
else if (sortDescriptors)
return [objects sortedArrayUsingDescriptors:sortDescriptors];
return sortedObjects;
return [objects copy];
}
- (void)rearrangeObjects
{
// Rearranging reapplies the selection criteria and may cause objects to disappear,
// so take care of the selection.
//
// Sometimes rearrangeObjects is called by setContent which may cause two rounds of
// selection preservation. This is okay because setContent temporarily clears the
// selection and so this code below ends up preserving nothing in that case.
var oldSelection = nil,
oldSelectionIndexes = [[self selectionIndexes] copy];
if ([self preservesSelection])
oldSelection = [self selectedObjects];
// Avoid out of bounds selections.
_selectionIndexes = [CPIndexSet indexSet];
[self _setArrangedObjects:[self arrangeObjects:[self contentArray]]];
if (oldSelection)
[self setSelectedObjects:oldSelection];
else
[self setSelectionIndexes:oldSelectionIndexes];
[self willChangeValueForKey:@"arrangedObjects"];
[self _rearrangeObjects];
[self didChangeValueForKey:@"arrangedObjects"];
}
- (void)_setArrangedObjects:(id)value
/*
Like rearrangeObjects but don't fire any change notifications.
@ignore
*/
- (void)_rearrangeObjects
{
/*
Rearranging reapplies the selection criteria and may cause objects to disappear,
so take care of the selection.
*/
var oldSelectedObjects = nil,
oldSelectionIndexes = nil;
if ([self preservesSelection])
oldSelectedObjects = [self selectedObjects];
else
oldSelectionIndexes = [self selectionIndexes];
[self __setArrangedObjects:[self arrangeObjects:[self contentArray]]];
if ([self preservesSelection])
[self __setSelectedObjects:oldSelectedObjects];
else
[self __setSelectionIndexes:oldSelectionIndexes];
}
- (void)__setArrangedObjects:(id)value
{
if (_arrangedObjects === value)
return;
@@ -245,7 +277,6 @@
return _arrangedObjects;
}
- (CPArray)sortDescriptors
{
return _sortDescriptors;
@@ -257,7 +288,9 @@
return;
_sortDescriptors = [value copy];
[self rearrangeObjects];
// Use the non-notification version since arrangedObjects already depends
// on sortDescriptors.
[self _rearrangeObjects];
}
- (CPPredicate)filterPredicate
@@ -266,12 +299,23 @@
}
- (void)setFilterPredicate:(CPPredicate)value
{
[self __setFilterPredicate:value];
}
/*
Like setFilterPredicate but don't fire any change notifications.
@ignore
*/
- (void)__setFilterPredicate:(CPPredicate)value
{
if (_filterPredicate === value)
return;
_filterPredicate = value;
[self rearrangeObjects];
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
[self _rearrangeObjects];
}
- (BOOL)alwaysUsesMultipleValuesMarker
@@ -298,8 +342,26 @@
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
if ([_selectionIndexes isEqualToIndexSet:indexes])
return NO;
[self __setSelectionIndexes:indexes];
}
/*
Like setSelectionIndex but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectionIndex:(int)theIndex
{
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
}
/*
Like setSelectionIndexes but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
{
if (!indexes)
indexes = [CPIndexSet indexSet];
if (![indexes count])
{
@@ -316,14 +378,11 @@
indexes = [CPIndexSet indexSetWithIndex:objectsCount-1];
}
[self willChangeValueForKey:@"selectionIndexes"];
[self _selectionWillChange];
if ([_selectionIndexes isEqualToIndexSet:indexes])
return NO;
_selectionIndexes = [indexes copy];
[self _selectionDidChange];
[self didChangeValueForKey:@"selectionIndexes"];
// 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.
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
@@ -335,10 +394,25 @@
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
return objects || [_CPObservableArray array];
return [_CPObservableArray arrayWithArray:(objects || [])];
}
- (BOOL)setSelectedObjects:(CPArray)objects
{
[self willChangeValueForKey:@"selectionIndexes"];
[self _selectionWillChange];
[self __setSelectedObjects:objects];
[self didChangeValueForKey:@"selectionIndexes"];
[self _selectionDidChange];
}
/*
Like setSelectedObjects but don't fire any change notifications.
@ignore
*/
- (BOOL)__setSelectedObjects:(CPArray)objects
{
var set = [CPIndexSet indexSet],
count = [objects count],
@@ -352,35 +426,35 @@
[set addIndex:index];
}
[self setSelectionIndexes:set];
[self __setSelectionIndexes:set];
return YES;
}
//Moving selection
-(BOOL)canSelectPrevious
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
-(BOOL)canSelectNext
-(void)selectPrevious:(id)sender
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1;
}
var index = [[self selectionIndexes] firstIndex] - 1;
-(void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1 || 0;
if (index < [[self arrangedObjects] count])
if (index >= 0)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
-(void)selectPrevious:(id)sender
- (BOOL)canSelectNext
{
var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1;
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
if (index >= 0)
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
if (index < [[self arrangedObjects] count])
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
@@ -391,30 +465,63 @@
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
[_contentObject addObject:object];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self setFilterPredicate:nil];
[self __setFilterPredicate:nil];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
if (_selectsInsertedObjects)
{
[self setSelectionIndex:pos];
}
[self __setSelectionIndex:pos];
else
{
[self willChangeValueForKey:@"selectionIndexes"];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
[self didChangeValueForKey:@"selectionIndexes"];
}
}
else
[self rearrangeObjects];
[self _rearrangeObjects];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
if ([self selectsInsertedObjects])
[self __setSelectionIndex:anIndex];
else
[[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1];
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)removeObject:(id)object
@@ -424,16 +531,18 @@
[self willChangeValueForKey:@"content"];
[_contentObject removeObject:object];
[self didChangeValueForKey:@"content"];
if ([_filterPredicate evaluateWithObject:object])
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
[self willChangeValueForKey:@"selectionIndexes"];
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
var pos = [_arrangedObjects indexOfObject:object];
[_arrangedObjects removeObjectAtIndex:pos];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
[self didChangeValueForKey:@"selectionIndexes"];
}
[self didChangeValueForKey:@"content"];
}
-(void)add:(id)sender
@@ -489,13 +598,33 @@
- (void)_removeObjects:(CPArray)objects
{
var contentArray = [self contentArray],
count = [objects count];
[self willChangeValueForKey:@"content"];
[_contentObject removeObjectsInArray:objects];
for (var i=0; i<count; i++)
[contentArray removeObject:[objects objectAtIndex:i]];
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
[self setContent:contentArray];
[arrangedObjects removeObjectsInArray:objects];
var objectsCount = [arrangedObjects count],
selectionIndexes = [CPIndexSet indexSet];
if ([self preservesSelection] || [self avoidsEmptySelection])
{
selectionIndexes = [CPIndexSet indexSetWithIndex:position];
// Remove the selection if there are no objects
if (objectsCount <= 0)
selectionIndexes = [CPIndexSet indexSet];
// Shift selection to last object if position is out of bounds
else if (position >= objectsCount)
selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
_selectionIndexes = selectionIndexes;
[self didChangeValueForKey:@"content"];
}
- (BOOL)canInsert
+93 -48
View File
@@ -19,25 +19,25 @@
* 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 "CPView.j"
// CPBorderType
CPNoBorder = 0;
CPLineBorder = 1;
CPLineBorder = 1;
CPBezelBorder = 2;
CPGrooveBorder = 3;
@implementation CPBox : CPView
{
CPBorderType _borderType;
CPColor _borderColor;
CPColor _fillColor;
float _cornerRadius;
float _borderWidth;
CPSize _contentMargin;
CPView _contentView;
}
@@ -50,18 +50,19 @@ CPGrooveBorder = 3;
[box setFrameFromContentFrame:[aView frame]];
[enclosingView replaceSubview:aView with:box];
[box setContentView:aView];
return box;
}
- (id)initWithFrame:(CPRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self)
{
_borderType = CPBezelBorder;
_fillColor = [CPColor clearColor];
_borderColor = [CPColor blackColor];
@@ -69,7 +70,9 @@ CPGrooveBorder = 3;
_contentMargin = CGSizeMake(0.0, 0.0);
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[self setAutoresizesSubviews:YES];
[self addSubview:_contentView];
}
@@ -161,9 +164,10 @@ CPGrooveBorder = 3;
return;
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
[aView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[self replaceSubview:_contentView with:aView];
_contentView = aView;
_contentView = aView;
}
- (CPSize)contentViewMargins
@@ -175,7 +179,7 @@ CPGrooveBorder = 3;
{
if(size.width < 0 || size.height < 0)
[CPException raise:CPGenericException reason:@"Margins must be positive"];
_contentMargin = CGSizeMakeCopy(size);
[self setNeedsDisplay:YES];
}
@@ -189,56 +193,97 @@ CPGrooveBorder = 3;
- (void)sizeToFit
{
var contentFrame = [_contentView frame];
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
contentFrame.size.height + _contentMargin.height * 2)];
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
}
- (void)drawRect:(CPRect)rect
{
if (_borderType === CPNoBorder)
return;
var bounds = [self bounds],
aContext = [[CPGraphicsContext currentContext] graphicsPort],
border2 = _borderWidth/2,
context = [[CPGraphicsContext currentContext] graphicsPort];
strokeRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth),
fillRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth);
CGContextSetFillColor(context, [self fillColor]);
CGContextSetFillColor(aContext, [self fillColor]);
CGContextSetStrokeColor(aContext, [self borderColor]);
CGContextSetLineWidth(aContext, _borderWidth);
switch(_borderType)
switch (_borderType)
{
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
break;
case CPBezelBorder:
var sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
sideGray = 190.0 / 255.0,
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
borderWidth = _borderWidth;
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
CGContextStrokePath(aContext);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
CGContextStrokePath(aContext);
break;
while (borderWidth--)
bounds = CPDrawTiledRects(bounds, bounds, sides, grays);
default: break;
CGContextFillRect(context, bounds);
break;
default:
bounds = CGRectInset(bounds, _borderWidth / 2.0, _borderWidth / 2.0);
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, _borderWidth);
CGContextFillRoundedRectangleInRect(context, bounds, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(context, bounds, _cornerRadius, YES, YES, YES, YES);
break;
}
}
@end
var CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
CPBoxFillColorKey = @"CPBoxFillColorKey",
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
@implementation CPBox (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
_contentView = [self subviews][0];
[self setAutoresizesSubviews:YES];
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
}
@end
+87 -42
View File
@@ -74,6 +74,9 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed");
CPButtonDefaultHeight = 24.0;
CPButtonImageOffset = 3.0;
/*!
@ingroup appkit
@class CPButton
@@ -89,9 +92,6 @@ CPButtonStateMixed = CPThemeState("mixed");
CPString _title;
CPString _alternateTitle;
CPImage _image;
CPImage _alternateImage;
CPInteger _showsStateBy;
CPInteger _highlightsBy;
BOOL _imageDimsWhenDisabled;
@@ -127,8 +127,8 @@ CPButtonStateMixed = CPThemeState("mixed");
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -145,7 +145,7 @@ CPButtonStateMixed = CPThemeState("mixed");
_controlSize = CPRegularControlSize;
_keyEquivalent = "";
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle];
@@ -284,18 +284,12 @@ CPButtonStateMixed = CPThemeState("mixed");
- (void)setImage:(CPImage)anImage
{
if (_image === anImage)
return;
_image = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
[self setValue:anImage forThemeAttribute:@"image"];
}
- (CPImage)image
{
return _image;
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
}
/*!
@@ -304,13 +298,7 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (void)setAlternateImage:(CPImage)anImage
{
if (_alternateImage === anImage)
return;
_alternateImage = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
}
/*!
@@ -318,7 +306,17 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (CPImage)alternateImage
{
return _alternateImage;
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
}
- (void)setImageOffset:(float)theImageOffset
{
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
}
- (float)imageOffset
{
return [self valueForThemeAttribute:@"image-offset"];
}
- (void)setShowsStateBy:(CPInteger)aMask
@@ -468,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (void)sizeToFit
{
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
[self layoutSubviews];
var size,
contentView = [self ephemeralSubviewNamed:@"content-view"];
if (contentView)
{
[contentView sizeToFit];
size = [contentView frameSize];
}
else
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"];
@@ -525,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
if (contentView)
{
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
@@ -540,14 +551,6 @@ CPButtonStateMixed = CPThemeState("mixed");
}
}
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
{
if (shouldBeDefaultButton)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)setBordered:(BOOL)shouldBeBordered
{
if (shouldBeBordered)
@@ -570,6 +573,27 @@ CPButtonStateMixed = CPThemeState("mixed");
- (void)setKeyEquivalent:(CPString)aString
{
_keyEquivalent = aString || @"";
// Check if the key equivalent is the enter key
// Treat \r and \n as the same key equivalent. See issue #710.
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)viewWillMoveToWindow:(CPWindow)aWindow
{
var selfWindow = [self window];
if (selfWindow === aWindow || aWindow === nil)
return;
if ([selfWindow defaultButton] === self)
[selfWindow setDefaultButton:nil];
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
[aWindow setDefaultButton:self];
}
/*!
@@ -602,6 +626,10 @@ CPButtonStateMixed = CPThemeState("mixed");
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
// Don't handle the key equivalent for the default window because the window will handle it for us
if ([[self window] defaultButton] === self)
return NO;
if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
return NO;
@@ -629,7 +657,11 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey";
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
@implementation CPButton (CPCoding)
@@ -645,14 +677,22 @@ var CPButtonImageKey = @"CPButtonImageKey",
{
_controlSize = CPRegularControlSize;
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -668,13 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_image forKey:CPButtonImageKey];
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
[aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
if (_keyEquivalent)
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
}
@end
+2 -1
View File
@@ -22,6 +22,7 @@
@import "CPButton.j"
CPCheckBoxImageOffset = 4.0;
@implementation CPCheckBox : CPButton
{
@@ -55,7 +56,7 @@
[self setImagePosition:CPImageLeft];
[self setAlignment:CPLeftTextAlignment];
[self setBordered:YES];
[self setBordered:NO];
}
return self;
+52 -22
View File
@@ -297,7 +297,7 @@
*/
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
{
if (_selectionIndexes == anIndexSet || !_isSelectable)
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
return;
var index = CPNotFound;
@@ -312,8 +312,10 @@
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self]
[_delegate collectionViewDidChangeSelection:self];
}
/*!
@@ -737,9 +739,12 @@
@end
@implementation CPCollectionView (KeyboardInteraction)
- (CPIndexSet)_selectionForEvent:(CPEvent)anEvent withNewIndex:(int)anIndex direction:(int)aDirection
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
{
if (_allowsMultipleSelection && [anEvent modifierFlags] & CPShiftKeyMask)
anIndex = MIN(MAX(anIndex, 0), [[self items] count]-1);
if (_allowsMultipleSelection && shouldExpand)
{
var indexes = [_selectionIndexes copy],
bottomAnchor = [indexes firstIndex],
@@ -754,7 +759,8 @@
else
indexes = [CPIndexSet indexSetWithIndex:anIndex];
return indexes;
[self setSelectionIndexes:indexes];
[self _scrollToSelection];
}
- (void)_scrollToSelection
@@ -771,26 +777,36 @@
if (index === CPNotFound)
index = [[self items] count];
index = MAX(index - 1, 0);
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
}
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]];
[self _scrollToSelection];
- (void)moveLeftAndModifySelection:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
}
- (void)moveRight:(id)sender
{
var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1);
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
}
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]];
[self _scrollToSelection];
- (void)moveRightAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
}
- (void)moveDown:(id)sender
{
var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1);
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
}
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]];
[self _scrollToSelection];
- (void)moveDownAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
}
- (void)moveUp:(id)sender
@@ -799,10 +815,16 @@
if (index == CPNotFound)
index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]);
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
}
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]];
[self _scrollToSelection];
- (void)moveUpAndModifySelection:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
}
- (void)deleteBackward:(id)sender
@@ -847,11 +869,13 @@
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding)
@@ -872,6 +896,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
@@ -898,6 +925,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
+64 -68
View File
@@ -56,18 +56,12 @@ var cachedBlackColor,
/*!
@ingroup appkit
@code CPColor
\c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.</p>
<p>It also provides some class helper methods that
returns instances of commonly used colors.</p>
<p>The class does not have a \c -set: method
like NextStep based frameworks to change the color of
the current context. To change the color of the current
context, use CGContextSetFillColor().
*/
@implementation CPColor : CPObject
{
@@ -82,12 +76,12 @@ var cachedBlackColor,
Each component should be between the range of 0.0 to 1.0. For
the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent.
@param red the red component of the color
@param green the green component of the color
@param blue the blue component of the color
@param alpha the alpha component
@return a color initialized to the values specified
*/
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -97,17 +91,17 @@ var cachedBlackColor,
/*!
@deprecated in favor of colorWithRed:green:blue:alpha:
Creates a color in the RGB color space, with an alpha value.
Each component should be between the range of 0.0 to 1.0. For
the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent.
@param red the red component of the color
@param green the green component of the color
@param blue the blue component of the color
@param alpha the alpha component
@return a color initialized to the values specified
*/
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -119,10 +113,10 @@ var cachedBlackColor,
/*!
Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@param alpha the alpha component between 0.0 and 1.0
@return a color initialized to the values specified
*/
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha
@@ -132,13 +126,13 @@ var cachedBlackColor,
/*!
@deprecated in favor of colorWithWhite:apha:
Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@param white a float between 0.0 and 1.0
@param alpha the alpha component between 0.0 and 1.0
@return a color initialized to the values specified
*/
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
@@ -148,11 +142,11 @@ var cachedBlackColor,
/*!
Creates a new color in HSB space.
@param hue the hue value
@param saturation the saturation value
@param brightness the brightness value
@return the initialized color
*/
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
@@ -162,16 +156,16 @@ var cachedBlackColor,
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
{
if(saturation === 0.0)
if (saturation === 0.0)
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
var f = hue % 60,
p = (brightness * (100 - saturation)) / 10000,
q = (brightness * (6000 - saturation * f)) / 600000,
t = (brightness * (6000 - saturation * (60 -f))) / 600000,
b = brightness / 100.0;
switch(FLOOR(hue / 60))
switch (FLOOR(hue / 60))
{
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
@@ -194,7 +188,8 @@ var cachedBlackColor,
*/
+ (CPColor)colorWithHexString:(string)hex
{
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
var rgba = hexToRGB(hex);
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
}
/*!
@@ -397,7 +392,7 @@ var cachedBlackColor,
/*!
Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
@param aString a CSS color string
@return a color initialized to the value in the css string
*/
@@ -409,23 +404,23 @@ var cachedBlackColor,
/* @ignore */
- (id)_initWithCSSString:(CPString)aString
{
if(aString.indexOf("rgb") == CPNotFound)
if (aString.indexOf("rgb") == CPNotFound)
return nil;
self = [super init];
var startingIndex = aString.indexOf("(");
var parts = aString.substring(startingIndex+1).split(',');
_components = [
parseInt(parts[0], 10) / 255.0,
parseInt(parts[1], 10) / 255.0,
parseInt(parts[2], 10) / 255.0,
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
]
];
_cssString = aString;
return self;
}
@@ -433,7 +428,7 @@ var cachedBlackColor,
- (id)_initWithRGBA:(CPArray)components
{
self = [super init];
if (self)
{
_components = components;
@@ -454,14 +449,14 @@ var cachedBlackColor,
- (id)_initWithPatternImage:(CPImage)anImage
{
self = [super init];
if (self)
{
_patternImage = anImage;
_cssString = "url(\"" + [_patternImage filename] + "\")";
_components = [0.0, 0.0, 0.0, 1.0];
}
return self;
}
@@ -523,17 +518,17 @@ var cachedBlackColor,
/*!
Returns a new color with the same RGB as the receiver but a new alpha component.
@param anAlphaComponent the alpha component for the new color
@return a new color object
*/
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
{
var components = _components.slice();
components[components.length - 1] = anAlphaComponent;
return [[[self class] alloc] _initWithRGBA:components];
}
@@ -552,35 +547,38 @@ var cachedBlackColor,
var red = ROUND(_components[_redComponent] * 255.0),
green = ROUND(_components[_greenComponent] * 255.0),
blue = ROUND(_components[_blueComponent] * 255.0);
var max = MAX(red, green, blue),
min = MIN(red, green, blue),
delta = max - min;
var brightness = max / 255.0,
saturation = (max != 0) ? delta / max : 0;
var hue;
if(saturation == 0)
if (saturation == 0)
{
hue = 0;
}
else
{
var rr = (max - red) / delta;
var gr = (max - green) / delta;
var br = (max - blue) / delta;
if (red == max)
hue = br - gr;
else if (green == max)
hue = 2 + rr - br;
else
hue = 4 + gr - rr;
hue /= 6;
if (hue < 0)
hue++;
}
return [
ROUND(hue * 360.0),
ROUND(saturation * 100.0),
@@ -699,10 +697,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, rgbToHex, byteToHex;
var hexCharacters = "0123456789ABCDEF";
/*!
Used for the CPColor \c +colorWithHexString: implementation
@@ -710,39 +706,39 @@ var hexToRGB, rgbToHex, byteToHex;
@class CPColor
@return an array of rgb components
*/
function hexToRGB(hex)
var hexToRGB = function(hex)
{
if ( hex.length == 3 )
if (hex.length == 3)
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
if(hex.length != 6)
if (hex.length != 6)
return null;
hex = hex.toUpperCase();
for(var i=0; i<hex.length; i++)
if(hexCharacters.indexOf(hex.charAt(i)) == -1)
for (var i = 0; i < hex.length; i++)
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
return null;
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
return [red, green, blue, 1.0];
}
};
function rgbToHex(r,g,b) {
var rgbToHex = function(r,g,b)
{
return byteToHex(r) + byteToHex(g) + byteToHex(b);
}
};
function byteToHex(n) {
if (!n || isNaN(n)) return "00";
n = ROUND(MIN(255,MAX(0,256*n)));
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
}
var byteToHex = function(n)
{
if (!n || isNaN(n))
return "00";
// Toll-Free bridge CPColor to CGColor.
//CGColor.prototype.isa = CPColor;
//[CPColor initialize];
n = FLOOR(MIN(255, MAX(0, 256 * n)));
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
};
+68 -68
View File
@@ -35,7 +35,7 @@ var PREVIEW_HEIGHT = 20.0,
var SharedColorPanel = nil,
ColorPickerClasses = [];
/*
A color wheel
@global
@@ -52,7 +52,7 @@ CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265,
CPColorPickerViewHeight = 370;
/*!
/*!
@ingroup appkit
@class CPColorPanel
@@ -61,7 +61,7 @@ CPColorPickerViewHeight = 370;
obtain the panel, call the \c +sharedColorPanel method.
*/
@implementation CPColorPanel : CPPanel
{
{
_CPColorPanelToolbar _toolbar;
_CPColorPanelSwatches _swatchView;
_CPColorPanelPreview _previewView;
@@ -80,8 +80,8 @@ CPColorPickerViewHeight = 370;
int _mode;
}
/*!
A list of color pickers is collected here, and any color panel created will contain
/*!
A list of color pickers is collected here, and any color panel created will contain
any picker in this list up to this point. In other words, call before creating a color panel.
*/
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass
@@ -96,7 +96,7 @@ CPColorPickerViewHeight = 370;
{
if (!SharedColorPanel)
SharedColorPanel = [[CPColorPanel alloc] init];
return SharedColorPanel;
}
@@ -107,7 +107,7 @@ CPColorPickerViewHeight = 370;
+ (void)setPickerMode:(CPColorPanelMode)mode
{
var panel = [CPColorPanel sharedColorPanel];
[panel setMode: mode];
[panel setMode:mode];
}
/*
@@ -116,7 +116,7 @@ CPColorPickerViewHeight = 370;
*/
- (id)init
{
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
if (self)
@@ -125,14 +125,14 @@ CPColorPickerViewHeight = 370;
[self setTitle:@"Color Panel"];
[self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)];
}
return self;
}
@@ -143,12 +143,12 @@ CPColorPickerViewHeight = 370;
{
_color = aColor;
[_previewView setBackgroundColor: _color];
[CPApp sendAction:@selector(changeColor:) to:nil from:self];
if (_target && _action)
[CPApp sendAction:_action to:_target from:self];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPColorPanelColorDidChangeNotification
object:self];
@@ -165,7 +165,7 @@ CPColorPickerViewHeight = 370;
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
{
[self setColor:aColor];
if (bool)
[_activePicker setColor:_color];
}
@@ -232,30 +232,30 @@ CPColorPickerViewHeight = 370;
{
var picker = _colorPickers[[sender tag]],
view = [picker provideNewView:NO];
if (!view)
view = [picker provideNewView:YES];
if (view == _currentView)
return;
if (_currentView)
[view setFrame:[_currentView frame]];
else
{
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+32),
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
bounds = [[self contentView] bounds];
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin: CPPointMake(5, height)];
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin:CPPointMake(5, height)];
}
[_currentView removeFromSuperview];
[[self contentView] addSubview:view];
_currentView = view;
_activePicker = picker;
[picker setColor:[self color]];
}
@@ -285,7 +285,7 @@ CPColorPickerViewHeight = 370;
_colorPickers = [];
var count = [ColorPickerClasses count];
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
{
var currentPickerClass = ColorPickerClasses[i],
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
@@ -297,29 +297,29 @@ CPColorPickerViewHeight = 370;
bounds = [contentView bounds];
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
[_toolbar setAutoresizingMask: CPViewWidthSizable];
[_toolbar setAutoresizingMask: CPViewWidthSizable];
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
buttonForLater = nil;
for (var i=0; i<count; i++)
for (var i = 0; i < count; i++)
{
var image = [_colorPickers[i] provideNewButtonImage],
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage],
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i*(ICON_WIDTH+ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i * (ICON_WIDTH + ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
[button setTag:i];
[button setTarget:self];
[button setAction:@selector(_setPicker:)];
[button setBordered:NO];
[button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
[button setImage:image];
[button setAlternateImage:highlightImage];
[_toolbar addSubview:button];
if (!buttonForLater)
buttonForLater = button;
}
@@ -330,7 +330,7 @@ CPColorPickerViewHeight = 370;
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
[_previewView setColorPanel:self];
[_previewView setAutoresizingMask:CPViewWidthSizable];
[_previewView setAutoresizingMask:CPViewWidthSizable];
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
[previewBox setAutoresizingMask:CPViewWidthSizable];
@@ -338,7 +338,7 @@ CPColorPickerViewHeight = 370;
[previewBox addSubview:_previewView];
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
[_previewLabel setStringValue: "Preview:"];
[_previewLabel setStringValue:"Preview:"];
[_previewLabel setTextColor:[CPColor blackColor]];
[_previewLabel setAlignment:CPRightTextAlignment];
@@ -350,8 +350,8 @@ CPColorPickerViewHeight = 370;
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
[_swatchView setColorPanel: self];
[_swatchView setAutoresizingMask: CPViewWidthSizable];
[_swatchView setColorPanel:self];
[_swatchView setAutoresizingMask:CPViewWidthSizable];
[swatchBox addSubview:_swatchView];
@@ -367,7 +367,7 @@ CPColorPickerViewHeight = 370;
[opacityLabel setAlignment:CPRightTextAlignment];
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
[_opacitySlider setMinValue:0.0];
[_opacitySlider setMaxValue:1.0];
@@ -418,34 +418,34 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
-(id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self setBackgroundColor: [CPColor grayColor]];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
var whiteColor = [CPColor whiteColor];
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
var colorList = [self startingColorList];
_swatches = [];
for(var i=0; i < 50; i++)
{
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
[view setBackgroundColor:whiteColor];
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
[view addSubview:fillView];
[self addSubview: view];
_swatches.push(view);
}
return self;
}
@@ -471,10 +471,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
[CPColor yellowColor]
];
}
var cookieValue = eval(cookieValue);
var result = [];
for(var i=0; i<cookieValue.length; i++)
result.push([CPColor colorWithHexString: cookieValue[i]]);
@@ -487,10 +487,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
for(var i=0; i<_swatches.length; i++)
result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
var future = new Date();
future.setYear(2019);
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
}
@@ -520,7 +520,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
@@ -535,21 +535,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
return NO;
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
var swatch = _swatches[FLOOR(point.x / 13)];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
_dragColor = [[swatch subviews][0] backgroundColor];
var bounds = CPRectCreateCopy([swatch bounds]);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var dragView = [[CPView alloc] initWithFrame: bounds];
var dragView = [[CPView alloc] initWithFrame: bounds],
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:_dragColor];
[dragView addSubview:dragFillView];
[self dragView: dragView
@@ -568,14 +568,14 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
{
{
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard],
swatch = nil;
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@@ -590,9 +590,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
return self;
}
@@ -610,9 +610,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var pasteboard = [aSender draggingPasteboard];
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO;
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES];
}
@@ -626,19 +626,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
var bounds = CPRectMake(0, 0, 15, 15);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var dragView = [[CPView alloc] initWithFrame: bounds];
var dragView = [[CPView alloc] initWithFrame: bounds],
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:[self backgroundColor]];
[dragView addSubview:dragFillView];
[self dragView: dragView
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
offset: CPPointMake(0.0, 0.0)
@@ -650,7 +650,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
if (aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
}
+1 -1
View File
@@ -278,7 +278,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
if (self)
{
_active = NO;
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
[self drawBezelWithHighlight:NO];
+14 -4
View File
@@ -280,7 +280,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)trackMouse:(CPEvent)anEvent
{
var type = [anEvent type],
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
if (type === CPLeftMouseUp)
@@ -289,7 +289,6 @@ var CPControlBlackColor = [CPColor blackColor];
_trackingMouseDownFlags = 0;
}
else
{
if (type === CPLeftMouseDown)
@@ -337,9 +336,19 @@ var CPControlBlackColor = [CPColor blackColor];
[self highlight:YES];
[self setState:[self nextState]];
[self sendAction:[self action] to:[self target]];
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
try
{
[self sendAction:[self action] to:[self target]];
}
catch (e)
{
throw e;
}
finally
{
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
}
}
- (void)unhighlightButtonTimerDidFinish:(id)sender
@@ -545,6 +554,7 @@ var CPControlBlackColor = [CPColor blackColor];
return;
[self _reverseSetBinding];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
+17 -10
View File
@@ -92,21 +92,28 @@
domain = "; domain="+domain;
else
domain = "";
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#if PLATFORM(DOM)
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#else
_cookieValue = value;
_expires = expires;
#endif
}
/* @ignore */
- (CPString)_readCookieValue
{
var nameEQ = _cookieName + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return "";
#if PLATFORM(DOM)
var nameEQ = _cookieName + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
#endif
return "";
}
@end
+1 -1
View File
@@ -197,7 +197,7 @@ var currentCursor = nil,
+ (void)unhide
{
[self _setCursorCSS:[currentCursor _cssString]]
[self _setCursorCSS:[currentCursor _cssString]];
}
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
+4 -4
View File
@@ -262,7 +262,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10)
insetBounds = CGRectInset(bounds, 10, 10),
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
@@ -304,7 +304,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
{
var userInfo = [aTimer userInfo];
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
location:[userInfo objectForKey:@"location"]];
}
@@ -328,8 +328,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
{
if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
+26 -20
View File
@@ -21,6 +21,7 @@
*/
@import <Foundation/CPObject.j>
@import "CPText.j"
#include "CoreGraphics/CGGeometry.h"
@@ -178,7 +179,8 @@ CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil;
_CPEventPeriodicEventTimer = nil,
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
/*!
@ingroup appkit
@@ -521,10 +523,10 @@ var _CPEventPeriodicEventPeriod = 0,
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
{
var characters = [self charactersIgnoringModifiers],
modifierFlags = [self modifierFlags];
if (!aKeyEquivalent)
return NO;
if (new RegExp("[A-Z]").test(aKeyEquivalent))
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
aKeyEquivalentModifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
@@ -533,35 +535,39 @@ var _CPEventPeriodicEventPeriod = 0,
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
return NO;
return [characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
// Treat \r and \n as the same key equivalent. See issue #710.
if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
}
- (BOOL)_couldBeKeyEquivalent
{
// FIXME: More cases? Space?
return _type === CPKeyDown &&
((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
[_characters length] > 0) ||
[self _hasActionCharacter]);
}
if (_type !== CPKeyDown)
return NO;
- (BOOL)_hasActionCharacter
{
var characters = [self characters],
characterCount = [characters length];
var characterCount = _characters.length;
if (!characterCount)
return NO;
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
for(var i=0; i<characterCount; i++)
{
var c = [characters characterAtIndex:i];
switch(c)
switch(_characters.charAt(i))
{
case CPBackspaceCharacter:
case CPDeleteCharacter:
case CPDeleteFunctionKey:
case CPTabCharacter:
case CPCarriageReturnCharacter:
case CPNewlineCharacter:
case CPEscapeFunctionKey:
case CPPageUpFunctionKey:
case CPPageDownFunctionKey:
@@ -570,10 +576,10 @@ var _CPEventPeriodicEventPeriod = 0,
case CPRightArrowFunctionKey:
case CPDownArrowFunctionKey:
return YES;
default:
return NO;
}
}
// FIXME: More cases? Space?
return NO;
}
/*!
+67 -8
View File
@@ -28,7 +28,7 @@ var _CPFonts = {},
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
/*!
/*!
@ingroup appkit
@class CPFont
@@ -38,11 +38,22 @@ var _CPFonts = {},
{
CPString _name;
float _size;
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold;
CPString _cssString;
}
+ (void)initialize
{
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
if (systemFont)
_CPFontSystemFontFace = systemFont;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@@ -89,25 +100,64 @@ var _CPFonts = {},
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
{
self = [super init];
if (self)
{
_name = aName;
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self;
}
return self;
}
/*!
Returns the font size (in points)
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px)
*/
- (float)ascender
{
if (!_ascender)
[self _getMetrics];
return _ascender;
}
/*!
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
Thus, if the longest descender extends 2 points below the baseline, descender will return 2.
*/
- (float)descender
{
if (!_descender)
[self _getMetrics];
return _descender;
}
/*!
Returns the default line height.
NOTE: This was moved from NSFont to NSLayoutManager in Cocoa, but since there is no CPLayoutManager, it has been kept here.
*/
- (float)defaultLineHeightForFont
{
if (!_lineHeight)
[self _getMetrics];
return _lineHeight;
}
/*!
Returns the font size (in CSS px)
*/
- (float)size
{
@@ -140,6 +190,15 @@ var _CPFonts = {},
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
}
- (void)_getMetrics
{
var metrics = [CPString metricsOfFont:self];
_ascender = [metrics objectForKey:@"ascender"];
_descender = [metrics objectForKey:@"descender"];
_lineHeight = [metrics objectForKey:@"lineHeight"];
}
@end
var CPFontNameKey = @"CPFontNameKey",
+29 -15
View File
@@ -70,7 +70,7 @@ function CPPointMake(x, y)
*/
function CPRectInset(aRect, dX, dY)
{
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
}
@@ -96,13 +96,13 @@ function CPRectIntegral(aRect)
function CPRectIntersection(lhsRect, rhsRect)
{
var intersection = CPRectMake(
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
0, 0);
intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection);
intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection);
return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection;
}
@@ -160,13 +160,13 @@ function CPRectStandardize(aRect)
standardized.origin.x += width;
standardized.size.width = -width;
}
if (height < 0.0)
{
standardized.origin.y += height;
standardized.size.height = -height;
}
return standardized;
}
@@ -183,7 +183,7 @@ function CPRectUnion(lhsRect, rhsRect)
minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)),
maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect));
return CPRectMake(minX, minY, maxX - minX, maxY - minY);
}
@@ -222,8 +222,8 @@ function CPRectContainsPoint(aRect, aPoint)
{
return aPoint.x >= CPRectGetMinX(aRect) &&
aPoint.y >= CPRectGetMinY(aRect) &&
aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect);
aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect);
}
/*!
@@ -261,7 +261,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
*/
function CPRectEqualToRect(lhsRect, rhsRect)
{
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
CPSizeEqualToSize(lhsRect.size, rhsRect.size);
}
@@ -380,6 +380,20 @@ function CPRectIsNull(aRect)
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0;
}
/*!
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
with a line that's parallel to the side of inRect specified by edge.
The size of slice is determined by amount, which specifies the distance from edge.
slice and rem must not be NULL.
@group CGRect
*/
function CPDivideRect(inRect, slice, rem, amount, edge)
{
CGRectDivide(inRect, slice, rem, amount, edge);
}
/*!
Returns \c YES if the two CGSizes are identical.
@group CGSize
@@ -434,7 +448,7 @@ function CPStringFromRect(aRect)
function CPPointFromString(aString)
{
var comma = aString.indexOf(',');
return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) };
}
@@ -447,7 +461,7 @@ function CPPointFromString(aString)
function CPSizeFromString(aString)
{
var comma = aString.indexOf(',');
return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) };
}
@@ -460,7 +474,7 @@ function CPSizeFromString(aString)
function CPRectFromString(aString)
{
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) };
}
@@ -504,6 +518,6 @@ function CPPointMakeZero()
return CPPointMake(0, 0, 0);
}
/*!
/*!
@}
*/
+110
View File
@@ -0,0 +1,110 @@
/*
* CPGraphics.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2010, 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 "CPColor.j"
@import "CPGraphicsContext.j"
#include "CoreGraphics/CGGeometry.h"
function CPDrawTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* float[] */ grays)
{
if (sides.length != grays.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
var colors = [];
for (var i = 0; i < grays.length; ++i)
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
}
function CPDrawColorTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* CPColor[] */ colors)
{
if (sides.length != colors.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
var resultRect = _CGRectMakeCopy(boundsRect),
slice = _CGRectMakeZero(),
remainder = _CGRectMakeZero(),
context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextSetLineWidth(context, 1.0);
for (var sideIndex = 0; sideIndex < sides.length; ++sideIndex)
{
var side = sides[sideIndex];
CGRectDivide(resultRect, slice, remainder, 1.0, side);
resultRect = remainder;
slice = CGRectIntersection(slice, clipRect);
// Cocoa docs say that only slices that are within the clipRect are actually drawn
if (_CGRectIsEmpty(slice))
continue;
var minX, maxX, minY, maxY;
if (side == CPMinXEdge || side == CPMaxXEdge)
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetWidth(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice) + 0.5;
maxX = minX;
minY = _CGRectGetMinY(slice);
maxY = _CGRectGetMaxY(slice);
}
else // CPMinYEdge || CPMaxYEdge
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetHeight(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice);
maxX = _CGRectGetMaxX(slice);
minY = _CGRectGetMinY(slice) + 0.5;
maxY = minY;
}
CGContextBeginPath(context);
CGContextMoveToPoint(context, minX, minY);
CGContextAddLineToPoint(context, maxX, maxY);
CGContextSetStrokeColor(context, colors[sideIndex]);
CGContextStrokePath(context);
}
CGContextRestoreGState(context);
return resultRect;
}
+9 -4
View File
@@ -193,6 +193,9 @@ function CPAppKitImage(aFilename, aSize)
var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize)
return nil;
if (!imageOrSize.isa)
{
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
@@ -205,17 +208,19 @@ function CPAppKitImage(aFilename, aSize)
return imageOrSize;
}
- (void)setName:(CPString)aName
- (BOOL)setName:(CPString)aName
{
if (_name === aName)
return;
return YES;
if (imagesForNames[aName] === self)
imagesForNames[aName] = nil;
if (imagesForNames[aName])
return NO;
_name = aName;
imagesForNames[aName] = self;
return YES;
}
- (CPString)name
+96 -13
View File
@@ -35,7 +35,18 @@ CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
var CPImageViewShadowBackgroundColor = nil;
CPImageAlignCenter = 0;
CPImageAlignTop = 1;
CPImageAlignTopLeft = 2;
CPImageAlignTopRight = 3;
CPImageAlignLeft = 4;
CPImageAlignBottom = 5;
CPImageAlignBottomLeft = 6;
CPImageAlignBottomRight = 7;
CPImageAlignRight = 8;
var CPImageViewShadowBackgroundColor = nil,
CPImageViewEmptyPlaceholderImage = nil;
var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0,
@@ -52,14 +63,22 @@ var LEFT_SHADOW_INSET = 3.0,
*/
@implementation CPImageView : CPControl
{
DOMElement _DOMImageElement;
DOMElement _DOMImageElement;
BOOL _hasShadow;
CPView _shadowView;
BOOL _hasShadow;
CPView _shadowView;
BOOL _isEditable;
BOOL _isEditable;
CGRect _imageRect;
CGRect _imageRect;
CPImageAlignment _imageAlignment;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:[CPView class]];
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -120,7 +139,7 @@ var LEFT_SHADOW_INSET = 3.0,
var newImage = [self objectValue];
#if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : "";
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
#endif
var size = [newImage size];
@@ -191,6 +210,30 @@ var LEFT_SHADOW_INSET = 3.0,
[self hideOrDisplayContents];
}
/*!
Sets the type of image alignment that should be used to
render the image.
@param anImageAlignment the type of scaling to use
*/
- (void)setImageAlignment:(CPImageAlignment)anImageAlignment
{
if (_imageAlignment == anImageAlignment)
return;
_imageAlignment = anImageAlignment;
if (![self image])
return;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
- (unsigned)imageAlignment
{
return _imageAlignment;
}
/*!
Sets the type of image scaling that should be used to
render the image.
@@ -318,8 +361,45 @@ var LEFT_SHADOW_INSET = 3.0,
#endif
}
var x = (boundsWidth - width) / 2.0,
y = (boundsHeight - height) / 2.0;
var x, y;
switch (_imageAlignment)
{
case CPImageAlignLeft:
case CPImageAlignTopLeft:
case CPImageAlignBottomLeft:
x = 0.0;
break;
case CPImageAlignRight:
case CPImageAlignTopRight:
case CPImageAlignBottomRight:
x = boundsWidth - width;
break;
default:
x = (boundsWidth - width) / 2.0;
break;
}
switch (_imageAlignment)
{
case CPImageAlignTop:
case CPImageAlignTopLeft:
case CPImageAlignTopRight:
y = 0.0;
break;
case CPImageAlignBottom:
case CPImageAlignBottomLeft:
case CPImageAlignBottomRight:
y = boundsHeight - height;
break;
default:
y = (boundsHeight - height) / 2.0;
break;
}
#if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -380,10 +460,11 @@ var LEFT_SHADOW_INSET = 3.0,
@end
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding)
@@ -416,6 +497,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES];
@@ -450,6 +532,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
if (_isEditable)
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
+255
View File
@@ -0,0 +1,255 @@
/*
* CPKeyBinding.j
* AppKit
*
* Created by Nicholas Small.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
CPStandardKeyBindings = {
@"@.": @"cancelOperation:",
@"^a": @"moveToBeginningOfParagraph:",
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
@"^b": @"moveBackward:",
@"^$b": @"moveBackwardAndModifySelection:",
@"^~b": @"moveWordBackward:",
@"^~$b": @"moveWordBackwardAndModifySelection:",
@"^d": @"deleteForward:",
@"^e": @"moveToEndOfParagraph:",
@"^$e": @"moveToEndOfParagraphAndModifySelection:",
@"^f": @"moveForward:",
@"^$f": @"moveForwardAndModifySelection:",
@"^~f": @"moveWordForward:",
@"^~$f": @"moveWordForwardAndModifySelection:",
@"^h": @"deleteBackward:",
@"^k": @"deleteToEndOfParagraph:",
@"^l": @"centerSelectionInVisibleArea:",
@"^n": @"moveDown:",
@"^$n": @"moveDownAndModifySelection:",
@"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"],
@"^p": @"moveUp:",
@"^$p": @"moveUpAndModifySelection:",
@"^t": @"transpose:",
@"^v": @"pageDown:",
@"^$v": @"pageDownAndModifySelection:",
@"^y": @"yank:"
};
CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:";
CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:";
CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:";
CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:";
CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:";
CPStandardKeyBindings[CPTabCharacter] = @"insertTab:";
CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:";
CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:";
CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:";
CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:";
CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:";
CPStandardKeyBindings[CPF5FunctionKey] = @"complete:";
CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:";
CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:";
CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:";
CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:";
CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:";
CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:";
CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:";
CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:";
CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:";
CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"];
CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:";
CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"];
CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:";
CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:";
CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:";
CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:";
CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:";
CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:";
var CPKeyBindingCache = {};
@implementation CPKeyBinding : CPObject
{
CPString _key;
unsigned _modifierFlags;
CPArray _selectors;
CPString _cacheName;
}
+ (void)initialize
{
if ([self class] !== CPKeyBinding)
return;
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
}
+ (void)createKeyBindingsFromJSObject:(JSObject)anObject
{
var binding;
for (binding in anObject)
{
var components = binding.split(@""),
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
var selectors = anObject[binding];
if (![selectors isKindOfClass:CPArray])
selectors = [selectors];
var keyBinding = [[self alloc] initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors];
[self cacheKeyBinding:keyBinding];
}
}
+ (void)cacheKeyBinding:(CPKeyBinding)aBinding
{
if (!aBinding)
return;
CPKeyBindingCache[[aBinding _cacheName]] = aBinding;
}
+ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil];
return CPKeyBindingCache[[tempBinding _cacheName]];
}
+ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors];
}
- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors
{
self = [super init];
if (self)
{
_key = aKey;
_modifierFlags = aFlag;
_selectors = selectors;
// We normalize our key binding string in order to properly cache it.
// We want to ensure the modifiers are always in the same order.
var cacheName = [];
if (_modifierFlags & CPCommandKeyMask)
cacheName.push(@"@");
if (_modifierFlags & CPControlKeyMask)
cacheName.push(@"^");
if (_modifierFlags & CPAlternateKeyMask)
cacheName.push(@"~");
if (_modifierFlags & CPShiftKeyMask)
cacheName.push(@"$");
cacheName.push(_key);
_cacheName = cacheName.join(@"");
}
return self;
}
- (CPString)key
{
return _key;
}
- (unsigned)modifierFlags
{
return _modifierFlags;
}
- (CPArray)selectors
{
return _selectors;
}
- (CPString)_cacheName
{
return _cacheName;
}
- (BOOL)isEqual:(CPKeyBinding)rhs
{
return _key === [rhs key] && _modifierFlags === [rhs modifierFlags];
}
@end
+14 -2
View File
@@ -108,7 +108,7 @@ var CPBindingOperationAnd = 0,
count = allKeys.length;
while (count--)
[anObject unbind:[bindings objectForKey:allKeys[count]]]
[anObject unbind:[bindings objectForKey:allKeys[count]]];
[bindingsMap removeObjectForKey:[anObject hash]];
}
@@ -181,7 +181,19 @@ var CPBindingOperationAnd = 0,
valueTransformer;
if (valueTransformerName)
{
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
if (!valueTransformer)
{
var valueTransformerClass = CPClassFromString(valueTransformerName);
if (valueTransformerClass)
{
valueTransformer = [[valueTransformerClass alloc] init];
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
}
}
}
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
@@ -263,7 +275,7 @@ var CPBindingOperationAnd = 0,
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
[self unbind:aBinding];
[[CPKeyValueBinding alloc] initWithBinding:[anObject _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
}
- (CPDictionary)infoForBinding:(CPString)aBinding
+1 -1
View File
@@ -75,7 +75,7 @@ var _CPMenuBarVisible = NO,
id _delegate;
CPMenuItem _highlightedIndex;
int _highlightedIndex;
_CPMenuWindow _menuWindow;
}
+1 -1
View File
@@ -96,7 +96,7 @@ var SharedMenuManager = nil;
// Close Menu Event.
if (type === CPAppKitDefined)
return [self completeTracking]
return [self completeTracking];
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
+44 -3
View File
@@ -591,7 +591,8 @@ CPControlKeyMask
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
@@ -781,7 +782,48 @@ CPControlKeyMask
return [[self menu] highlightedItem] == self;
}
//
#pragma mark CPObject Overrides
/*!
Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied.
*/
- (id)copy
{
var item = [[CPMenuItem alloc] init];
// No point in going through accessors and doing lots of unnecessary state checking/updating
item._isSeparator = _isSeparator;
[item setTitle:_title];
[item setFont:_font];
[item setTarget:_target];
[item setAction:_action];
[item setEnabled:_isEnabled];
[item setHidden:_isHidden]
[item setTag:_tag];
[item setState:_state];
[item setImage:_image];
[item setAlternateImage:_alternateImage];
[item setOnStateImage:_onStateImage];
[item setOffStateImage:_offStateImage];
[item setMixedStateImage:_mixedStateImage];
[item setKeyEquivalent:_keyEquivalent];
[item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
[item setMnemonicLocation:_mnemonicLocation];
[item setAlternate:_isAlternate];
[item setIndentationLevel:_indentationLevel];
[item setToolTip:_toolTip];
[item setRepresentedObject:_representedObject];
return item;
}
- (id)mutableCopy
{
return [self copy];
}
#pragma mark Internal
/*
@ignore
@@ -860,7 +902,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
// int _state;
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
@@ -62,6 +62,7 @@ var SelectionColor = nil,
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setImageOffset:3.0];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
+8 -5
View File
@@ -39,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
var bundle = [CPBundle bundleForClass:self];
@@ -257,10 +257,13 @@ var SUBMENU_INDICATOR_COLOR = nil,
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
}
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
if ([[_menuItem menu] showsStateColumn])
{
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
}
@end
+1 -1
View File
@@ -43,7 +43,7 @@ var _CPMenuItemSelectionColor = nil,
return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
var bundle = [CPBundle bundleForClass:self];
+14 -4
View File
@@ -51,15 +51,20 @@
return [CPSet setWithObjects:"editable", "selection"];
}
- (id)init
{
return [self initWithContent:nil];
}
- (id)initWithContent:(id)aContent
{
self = [super init];
if (self)
if (self = [super init])
{
[self setContent:aContent];
[self setEditable:YES];
[self setObjectClass:[CPMutableDictionary class]];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
@@ -452,7 +457,12 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
[self didChangeValueForKey:keyPath];
}
[self removeObjectAtIndex:anIndex];
[super removeObjectAtIndex:anIndex];
}
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
{
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
}
- (void)addObject:(id)anObject
+88 -9
View File
@@ -624,7 +624,7 @@ CPOutlineViewDropOnItemIndex = -1;
if (_dropItem)
{
[_dropOperationFeedbackView blink];
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO]; //[self expandItem:_dropItem];
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
}
}
@@ -645,10 +645,18 @@ CPOutlineViewDropOnItemIndex = -1;
_shouldRetargetChildIndex = YES;
// set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo,
retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
_retargetedDropRow = [self rowForItem:retargetedChildItem];
if (_retargedChildIndex === [retargetedItemInfo.children count])
{
var retargetedChildItem = [retargetedItemInfo.children lastObject];
_retargetedDropRow = [self rowForItem:retargetedChildItem] + 1;
}
else
{
var retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
_retargetedDropRow = [self rowForItem:retargetedChildItem];
}
}
- (void)_draggingEnded
@@ -1102,7 +1110,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
_outlineView._shouldRetargetChildIndex = NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location],
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
@@ -1247,11 +1255,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
CGContextAddLineToPoint(context, 0.0, 0.0);
CGContextClosePath(context);
var isHighlighted = [self hasThemeState:CPThemeStateHighlighted];
var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]);
CGContextSetFillColor(context, color);
CGContextSetFillColor(context,
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
[self hasThemeState:CPThemeStateHighlighted]));
CGContextFillPath(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0.0, 0.0);
if(_angle === 0.0) {
CGContextAddLineToPoint(context, 4.5, 8.0);
CGContextAddLineToPoint(context, 9.0, 0.0);
} else {
CGContextAddLineToPoint(context, 4.5, 8.0);
}
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
CGContextStrokePath(context);
}
@end
var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey",
CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey",
CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey",
CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey";
@implementation CPOutlineView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// The root item has weight "0", thus represents the weight solely of its descendants.
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
_itemsForRows = [];
_itemInfosForItems = { };
_disclosureControlsForRows = [];
[self setIndentationMarkerFollowsDataView:YES];
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
_outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
_indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
_outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
_outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
[aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
[aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
}
@end
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
return isSelected
? (isHighlighted
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
: [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0])
: (isHighlighted
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
}
+3
View File
@@ -662,6 +662,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
minimumWidth += standardLeftMargin;
// To ensure the selected item is highlighted correctly, unset the highlighted item
[menu _highlightItemAtIndex:CPNotFound];
}
[menu setMinimumWidth:minimumWidth];
+17 -14
View File
@@ -27,26 +27,26 @@
/*!
@ingroup appkit
from this mailing list thread:
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
-----------------------------------
Creating a checkbox is easy enough:
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
That's basically all there is to it. Radio buttons are very similar,
the key difference is the introduction of a new class CPRadioGroup,
which defines which radio buttons are part of the same group:
[myRadioButton setRadioGroup:aRadioGroup];
Every radio button receives a unique radio group by default (so if you
do nothing further, they will all behave independently), but you can
use an existing radio button's group with other buttons as so:
button1 = [[CPRadio alloc] initWithFrame:aFrame];
...
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
@@ -55,13 +55,16 @@
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
radioGroup]];
...etc...
Here, all the radio buttons will act "together". [[button1 radioGroup]
allRadios] returns every button that's part of this group, and
[[button1 radioGroup] selectedRadio] returns the currently selected
option.
*/
CPRadioImageOffset = 4.0;
@implementation CPRadio : CPButton
{
CPRadioGroup _radioGroup;
@@ -95,7 +98,7 @@
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setRadioGroup:aRadioGroup];
@@ -109,8 +112,8 @@
[self setBordered:YES];
}
return self;
return self;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -141,7 +144,7 @@
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
if ([self state] === CPOnState)
[_radioGroup _setSelectedRadio:self];
}
+27 -37
View File
@@ -22,7 +22,6 @@
@import <Foundation/CPObject.j>
CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
@@ -39,7 +38,7 @@ CPDeleteForwardKeyCode = 46;
/*!
@ingroup appkit
@class CPResponder
Subclasses of CPResonder can be part of the responder chain.
*/
@implementation CPResponder : CPObject
@@ -105,42 +104,24 @@ CPDeleteForwardKeyCode = 46;
for (; index < count; ++index)
{
var event = events[index];
var event = events[index],
modifierFlags = [event modifierFlags],
character = [event charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
switch([event keyCode])
if (selectorNames)
{
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
break;
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
break;
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
break;
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
break;
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
break;
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
break;
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
break;
case CPReturnKeyCode:
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
break;
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
break;
for (var s = 0, scount = selectorNames.length; s < scount; s++)
{
var selector = selectorNames[s];
if (!selector)
continue;
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
if (!shift)
[self doCommandBySelector:@selector(insertTab:)];
else
[self doCommandBySelector:@selector(insertBackTab:)];
break;
default: [self insertText:[event characters]];
[self doCommandBySelector:CPSelectorFromString(selector)];
}
}
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
[self insertText:[event characters]];
}
}
@@ -240,6 +221,15 @@ CPDeleteForwardKeyCode = 46;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*!
Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
@param anEvent information about the key press
*/
- (void)flagsChanged:(CPEvent)anEvent
{
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*
FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event.
@@ -316,7 +306,7 @@ CPDeleteForwardKeyCode = 46;
if([self respondsToSelector:aSelector])
{
[self performSelector:aSelector withObject:anObject];
return YES;
}
@@ -367,10 +357,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
return self;
}
+313 -38
View File
@@ -37,23 +37,39 @@
*/
@implementation CPScrollView : CPView
{
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
CPView _bottomCornerView;
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
int _recursionCount;
int _recursionCount;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
CPBorderType _borderType;
}
+ (CPString)themeClass
{
return @"scrollview"
}
+ (CPDictionary)themeAttributes
{
return [CPDictionary dictionaryWithJSObject:{
@"bottom-corner-color": [CPColor whiteColor],
@"border-color": [CPColor blackColor]
}];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -68,14 +84,18 @@
_horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0;
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
_borderType = CPNoBorder;
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
[self addSubview:_contentView];
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
_bottomCornerView = [[CPView alloc] init];
[self addSubview:_bottomCornerView];
[self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES];
}
@@ -83,6 +103,65 @@
return self;
}
// Calculating Layout
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
{
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
scrollerWidth = [CPScroller scrollerWidth];
if (hFlag)
bounds.size.height -= scrollerWidth;
if (vFlag)
bounds.size.width -= scrollerWidth;
return bounds.size;
}
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
{
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
widthInset = contentSize.width - bounds.size.width,
heightInset = contentSize.height - bounds.size.height,
frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
scrollerWidth = [CPScroller scrollerWidth];
if (hFlag)
frameSize.height -= scrollerWidth;
if (vFlag)
frameSize.width -= scrollerWidth;
return frameSize;
}
+ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
{
switch (borderType)
{
case CPLineBorder:
case CPBezelBorder:
return _CGRectInset(bounds, 1.0, 1.0);
case CPGrooveBorder:
bounds = _CGRectInset(bounds, 2.0, 2.0);
++bounds.origin.y;
--bounds.size.height;
return bounds;
case CPNoBorder:
default:
return bounds;
}
}
- (CGRect)_insetBounds
{
return [[self class] _insetBounds:[self bounds] borderType:_borderType];
}
// Determining component sizes
/*!
Returns the size of the scroll view's content view.
@@ -176,7 +255,7 @@
// [_horizontalScroller setEnabled:NO];
}
[_contentView setFrame:[self bounds]];
[_contentView setFrame:[self _insetBounds]];
[_headerClipView setFrame:_CGRectMakeZero()];
--_recursionCount;
@@ -185,7 +264,7 @@
}
var documentFrame = [documentView frame], // the size of the whole document
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
headerClipViewFrame = [self _headerClipViewFrame],
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
@@ -235,11 +314,10 @@
if (shouldShowVerticalScroller)
{
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
var verticalScrollerY =
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
if (shouldShowHorizontalScroller)
verticalScrollerHeight -= horizontalScrollerHeight;
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
@@ -255,7 +333,7 @@
{
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
}
else if (wasShowingHorizontalScroller)
{
@@ -267,9 +345,36 @@
[_headerClipView setFrame:headerClipViewFrame];
[_cornerView setFrame:[self _cornerViewFrame]];
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
--_recursionCount;
}
// Managing Graphics Attributes
/*!
Sets the type of border to be drawn around the view.
*/
- (void)setBorderType:(CPBorderType)borderType
{
if (_borderType == borderType)
return;
_borderType = borderType;
[self reflectScrolledClipView:_contentView];
[self setNeedsDisplay:YES];
}
/*!
Returns the border type drawn around the view.
*/
- (CPBorderType)borderType
{
return _borderType;
}
// Managing Scrollers
/*!
Sets the scroll view's horizontal scroller.
@@ -316,8 +421,10 @@
if (_hasHorizontalScroller && !_horizontalScroller)
{
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
var bounds = [self _insetBounds];
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])];
}
[self reflectScrolledClipView:_contentView];
@@ -377,8 +484,10 @@
if (_hasVerticalScroller && !_verticalScroller)
{
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
var bounds = [self _insetBounds];
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))];
}
[self reflectScrolledClipView:_contentView];
@@ -453,11 +562,11 @@
if (!_cornerView)
return _CGRectMakeZero();
var bounds = [self bounds],
var bounds = [self _insetBounds],
frame = [_cornerView frame];
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
frame.origin.y = 0;
frame.origin.y = _CGRectGetMinY(bounds);
return frame;
}
@@ -469,7 +578,7 @@
if (!headerView)
return _CGRectMakeZero();
var frame = [self bounds];
var frame = [self _insetBounds];
frame.size.height = _CGRectGetHeight([headerView frame]);
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
@@ -477,6 +586,42 @@
return frame;
}
- (CGRect)_bottomCornerViewFrame
{
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
return CGRectMakeZero();
var verticalFrame = [[self verticalScroller] frame],
bottomCornerFrame = CGRectMakeZero();
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
return bottomCornerFrame;
}
- (void)setBottomCornerView:(CPView)aBottomCornerView
{
if (_bottomCornerView === aBottomCornerView)
return;
[_bottomCornerView removeFromSuperview];
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
[self addSubview:aBottomCornerView];
_bottomCornerView = aBottomCornerView;
[self _updateCornerAndHeaderView];
}
- (CPView)bottomCornerView
{
return _bottomCornerView;
}
/* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
{
@@ -662,14 +807,138 @@
return _verticalPageScroll;
}
// CPView Overrides
- (void)drawRect:(CPRect)aRect
{
[super drawRect:aRect];
if (_borderType == CPNoBorder)
return;
var strokeRect = [self bounds],
context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetLineWidth(context, 1);
switch (_borderType)
{
case CPLineBorder:
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
break;
case CPBezelBorder:
[self _drawGrayBezelInContext:context bounds:strokeRect];
break;
case CPGrooveBorder:
[self _drawGrooveInContext:context bounds:strokeRect];
break;
default:
break;
}
}
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
{
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
var y = _CGRectGetMinY(aRect) + 0.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]);
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
var x = _CGRectGetMaxX(aRect) - 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5);
x = _CGRectGetMinX(aRect) + 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
CGContextStrokePath(context);
}
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
{
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0/255.0 alpha:1.0]);
var y = _CGRectGetMinY(aRect) + 0.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
var x = _CGRectGetMaxX(aRect) - 1.5;
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0);
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0);
y = _CGRectGetMaxY(aRect) - 1.5;
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
x = _CGRectGetMinX(aRect) + 0.5;
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect));
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor whiteColor]);
var rect = _CGRectOffset(aRect, 1.0, 1.0);
rect.size.width -= 1.0;
rect.size.height -= 1.0;
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
CGContextBeginPath(context);
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]);
y = _CGRectGetMinY(aRect) + 2.5;
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y);
CGContextStrokePath(context);
}
// CPResponder Overrides
/*!
Handles a scroll wheel event from the user.
@param anEvent the scroll wheel event
*/
- (void)scrollWheel:(CPEvent)anEvent
{
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll
deltaY:[anEvent deltaY] * _verticalLineScroll];
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
}
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
@@ -677,17 +946,15 @@
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds],
contentFrame = [_contentView frame],
enclosingScrollView = [self enclosingScrollView],
extraX = 0,
extraY = 0;
enclosingScrollView = [self enclosingScrollView];
// We want integral bounds!
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)];
extraX = ((contentBounds.origin.x - constrainedOrigin.x) / _horizontalLineScroll) * [enclosingScrollView horizontalLineScroll];
extraY = ((contentBounds.origin.y - constrainedOrigin.y) / _verticalLineScroll) * [enclosingScrollView verticalLineScroll];
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
extraX = contentBounds.origin.x - constrainedOrigin.x,
extraY = contentBounds.origin.y - constrainedOrigin.y;
[_contentView scrollToPoint:constrainedOrigin];
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
@@ -758,7 +1025,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey",
CPScrollViewBorderTypeKey = "CPScrollViewBorderTypeKey";
@implementation CPScrollView (CPCoding)
@@ -781,6 +1049,9 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[self addSubview:_headerClipView];
}
_bottomCornerView = [[CPView alloc] init];
[self addSubview:_bottomCornerView];
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -788,6 +1059,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
// Do 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.
@@ -817,6 +1090,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
}
@end
+87 -73
View File
@@ -41,9 +41,9 @@ CPNoScrollerParts = 0;
CPOnlyScrollerArrows = 1;
CPAllScrollerParts = 2;
/*!
/*!
@ingroup appkit
@class CPScroller
@class CPScroller
*/
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
@@ -79,17 +79,18 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
forKeys:[ @"knob-slot-color",
@"decrement-line-color",
@"increment-line-color",
@"knob-color",
@"decrement-line-size",
@"increment-line-size",
@"track-inset",
@"knob-inset",
@"minimum-knob-length"]];
return [CPDictionary dictionaryWithJSObject:{
@"scroller-width": 15.0,
@"knob-slot-color": [CPColor lightGrayColor],
@"decrement-line-color": [CPNull null],
@"increment-line-color": [CPNull null],
@"knob-color": [CPColor grayColor],
@"decrement-line-size":_CGSizeMakeZero(),
@"increment-line-size":_CGSizeMakeZero(),
@"track-inset":_CGInsetMakeZero(),
@"knob-inset": _CGInsetMakeZero(),
@"minimum-knob-length":21.0
}]
}
@@ -98,7 +99,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_controlSize = CPRegularControlSize;
@@ -106,7 +107,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setFloatValue:0.0];
[self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
@@ -121,7 +122,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidth
{
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
}
/*!
@@ -130,7 +131,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
{
return 15.0;//_CPScrollerWidths[aControlSize];
return [self scrollerWidth];
}
/*!
@@ -180,10 +181,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
{
var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState];
}
@@ -205,25 +206,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPScrollerPart)testPart:(CGPoint)aPoint
{
aPoint = [self convertPoint:aPoint fromView:nil];
// The ordering of these tests is important. We check the knob and
// The ordering of these tests is important. We check the knob and
// page rects first since they may overlap with the arrows.
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
return CPScrollerKnob;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
return CPScrollerDecrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
return CPScrollerIncrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
return CPScrollerDecrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
return CPScrollerIncrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
return CPScrollerKnobSlot;
@@ -241,7 +242,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
if (_knobProportion === 1.0)
{
_usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
@@ -250,7 +251,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return;
}
@@ -260,8 +261,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds);
height = _CGRectGetHeight(bounds);
if ([self isVertical])
{
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
@@ -280,10 +281,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(height < decrementLineSize.height + incrementLineSize.height - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
@@ -309,10 +310,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(width < decrementLineSize.width + incrementLineSize.width - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
@@ -358,9 +359,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPView)createViewForPart:(CPScrollerPart)aPart
{
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -374,7 +375,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -388,12 +389,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
for (; index < count; ++index)
{
var part = PARTS_ARRANGEMENT[index];
if (index === 0)
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
else
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
if (view)
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
}
@@ -403,7 +404,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
Caches images for the scroll arrow and knob.
*/
- (void)drawParts
{
{
[self drawKnobSlot];
[self drawKnob];
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
@@ -426,37 +427,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (void)trackKnob:(CPEvent)anEvent
{
var type = [anEvent type];
if (type === CPLeftMouseUp)
{
_hitPart = CPScrollerNoPart;
return;
}
if (type === CPLeftMouseDown)
{
_trackingFloatValue = [self floatValue];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
}
else if (type === CPLeftMouseDragged)
{
var knobRect = [self rectForPart:CPScrollerKnob],
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
if (remainder <= 0)
[self setFloatValue:0.0];
else
{
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
[self setFloatValue:_trackingFloatValue + delta / remainder];
}
}
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[self sendAction:[self action] to:[self target]];
@@ -474,26 +475,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
[self highlight:NO];
[CPEvent stopPeriodicEvents];
_hitPart = CPScrollerNoPart;
return;
}
if (type === CPLeftMouseDown)
{
_trackingPart = [self hitPart];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent modifierFlags] & CPAlternateKeyMask)
{
if (_trackingPart == CPScrollerDecrementLine)
_hitPart = CPScrollerDecrementPage;
else if (_trackingPart == CPScrollerIncrementLine)
_hitPart = CPScrollerIncrementPage;
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{
var knobRect = [self rectForPart:CPScrollerKnob],
@@ -502,42 +503,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
_hitPart = CPScrollerKnob;
[self sendAction:[self action] to:[self target]];
[self sendAction:[self action] to:[self target]];
// Now just track the knob.
return [self trackKnob:anEvent];
}
}
[self highlight:YES];
[self sendAction:[self action] to:[self target]];
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
}
else if (type === CPLeftMouseDragged)
{
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{
var hitPart = [self testPart:[anEvent locationInWindow]];
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
{
_trackingPart = hitPart;
_hitPart = hitPart;
}
}
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
}
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
[self sendAction:[self action] to:[self target]];
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -569,15 +570,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
if (![self isEnabled])
return;
_hitPart = [self testPart:[anEvent locationInWindow]];
switch (_hitPart)
{
case CPScrollerKnob: return [self trackKnob:anEvent];
case CPScrollerDecrementLine:
case CPScrollerIncrementLine:
case CPScrollerDecrementLine:
case CPScrollerIncrementLine:
case CPScrollerDecrementPage:
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
}
@@ -603,19 +604,32 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
_partRects = [];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
// Adjust the size of the scroller if the size from cib
// isn't equal to the scrollerWidth
var frame = [self frame],
scrollerWidth = [CPScroller scrollerWidth];
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
frame.size.width = scrollerWidth;
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
frame.size.height = scrollerWidth;
[self setFrame:frame];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
}
+228 -129
View File
@@ -22,18 +22,27 @@
@import "CPTextField.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003;
CPSearchFieldSeparatorMenuItemTag = 1004;
var CPSearchFieldSearchImage = nil,
CPSearchFieldFindImage = nil,
CPSearchFieldCancelImage = nil,
CPSearchFieldCancelPressedImage = nil;
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
BUTTON_DEFAULT_HEIGHT = 22.0;
var RECENT_SEARCH_PREFIX = @" ";
/*!
@ingroup appkit
@class CPSearchField
@@ -54,6 +63,7 @@ var CPSearchFieldSearchImage = nil,
int _maximumRecents;
BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately;
BOOL _canResignFirstResponder;
CPTimer _partialStringTimer;
}
@@ -63,23 +73,22 @@ var CPSearchFieldSearchImage = nil,
return;
var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
_recentSearches = [CPArray array];
_maximumRecents = 10;
_sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil;
[self _initWithFrame:frame];
[self _init];
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
@@ -89,23 +98,28 @@ var CPSearchFieldSearchImage = nil,
return self;
}
- (void)_initWithFrame:(CGRect)frame
- (void)_init
{
_recentSearches = [CPArray array];
[self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
[self setContinuous:YES];
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
var bounds = [self bounds],
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
[self setCancelButton:cancelButton];
[self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
[self setSearchButton:searchButton];
[self resetSearchButton];
[self addSubview:_searchButton];
_canResignFirstResponder = YES;
}
// Managing Buttons
@@ -115,7 +129,15 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setSearchButton:(CPButton)button
{
_searchButton = button;
if (button != _searchButton)
{
[_searchButton removeFromSuperview];
_searchButton = button;
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
[self addSubview:_searchButton];
}
}
/*!
@@ -133,30 +155,13 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)resetSearchButton
{
var searchButtonImage,
action,
target,
button = [self searchButton];
if (_searchMenuTemplate === nil)
{
searchButtonImage = CPSearchFieldSearchImage;
action = @selector(_sendAction:);
target = self;
}
else
{
searchButtonImage = CPSearchFieldFindImage;
action = @selector(_showMenu:);
target = self;
}
var button = [self searchButton],
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
}
/*!
@@ -165,7 +170,18 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setCancelButton:(CPButton)button
{
_cancelButton = button;
if (button != _cancelButton)
{
[_cancelButton removeFromSuperview];
_cancelButton = button;
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[_cancelButton setTarget:self];
[_cancelButton setAction:@selector(_searchFieldCancel:)];
[self _updateCancelButtonVisibility];
[self addSubview:_cancelButton];
}
}
/*!
@@ -200,23 +216,25 @@ var CPSearchFieldSearchImage = nil,
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)searchTextRectForBounds:(CPRect)rect
- (CGRect)searchTextRectForBounds:(CGRect)rect
{
var leftOffset = 0, width = rect.size.width;
var leftOffset = 0,
width = _CGRectGetWidth(rect),
bounds = [self bounds];
if (_searchButton)
{
var searchRect = [_searchButton frame];
leftOffset = searchRect.origin.x + searchRect.size.width;
var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
}
if (_cancelButton)
{
var cancelRect = [_cancelButton frame];
width = cancelRect.origin.x - leftOffset;
var cancelRect = [self cancelButtonRectForBounds:bounds];
width = _CGRectGetMinX(cancelRect) - leftOffset;
}
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
}
/*!
@@ -224,9 +242,9 @@ var CPSearchFieldSearchImage = nil,
@param rect The current bounding rectangle for the search button.
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)searchButtonRectForBounds:(CPRect)rect
- (CGRect)searchButtonRectForBounds:(CGRect)rect
{
return [_searchButton frame];
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
}
/*!
@@ -234,9 +252,9 @@ var CPSearchFieldSearchImage = nil,
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
{
return [_cancelButton frame];
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
{
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
}
// Managing Menu Templates
@@ -254,9 +272,9 @@ var CPSearchFieldSearchImage = nil,
@param menu The menu template to use.
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
*/
- (void)setSearchMenuTemplate:(CPMenu)menu
- (void)setSearchMenuTemplate:(CPMenu)aMenu
{
_searchMenuTemplate = menu;
_searchMenuTemplate = aMenu;
[self resetSearchButton];
[self _loadRecentSearchList];
@@ -373,7 +391,7 @@ var CPSearchFieldSearchImage = nil,
// Private methods and subclassing
- (CPRect)contentRectForBounds:(CPRect)bounds
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds];
@@ -447,37 +465,78 @@ var CPSearchFieldSearchImage = nil,
[self _updateSearchMenu];
}
- (BOOL)trackMouse:(CPEvent)event
- (CPView)hitTest:(CGPoint)aPoint
{
var rect,
point,
location = [event locationInWindow];
point = [self convertPoint:location fromView:nil];
rect = [self searchButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self searchButton] trackMouse:event];
}
rect = [self cancelButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self cancelButton] trackMouse:event];
}
return [super trackMouse:event];
// Make sure a hit anywhere within the search field returns the search field itself
if (_CGRectContainsPoint([self frame], aPoint))
return self;
else
return nil;
}
- (CPMenu)_defaultSearchMenuTemplate
- (BOOL)resignFirstResponder
{
var template, item;
return _canResignFirstResponder && [super resignFirstResponder];
}
- (void)mouseDown:(CPEvent)anEvent
{
var location = [anEvent locationInWindow],
point = [self convertPoint:location fromView:nil];
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
{
if (_searchMenuTemplate == nil)
[self _sendAction:self];
else
[self _showMenu];
}
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
[_cancelButton mouseDown:anEvent];
else
[super mouseDown:anEvent];
}
/*!
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
template = [[CPMenu alloc] init];
No Recent Searches
If there are 1 more recent searches, it displays:
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
action:NULL
Recent Searches
recent search 1
recent search 2
etc.
---------------------
Clear Recent Searches
If you wish to add items before or after the template, you can. If you put items
before, a separator will automatically be placed before the default template item.
If you add items after the default template, it is your responsibility to add a separator.
To add a custom item:
item = [[CPMenuItem alloc] initWithTitle:@"google"
action:@selector(google:)
keyEquivalent:@""];
[item setTag:700];
[item setTarget:self];
[template addItem:item];
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
If you wish to maintain state in custom menu items that you add, you will need to maintain
the item state yourself, then in the action method of the custom items, modify the items
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
*/
- (CPMenu)defaultSearchMenuTemplate
{
var template = [[CPMenu alloc] init],
item;
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO];
@@ -490,15 +549,15 @@ var CPSearchFieldSearchImage = nil,
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
action:NULL
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
@@ -512,61 +571,96 @@ var CPSearchFieldSearchImage = nil,
if (_searchMenuTemplate === nil)
return;
var i, menu = [[CPMenu alloc] init],
var menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
for (i = 0; i < numberOfItems; i++)
for (var i = 0; i < numberOfItems; i++)
{
var item = [_searchMenuTemplate itemAtIndex:i],
tag = [item tag];
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag === CPSearchFieldRecentsMenuItemTag))
{
var itemAction, itemTarget;
switch (tag)
{
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
default: itemAction = [item action]; itemTarget = [item target]; break;
}
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[menu addItem:separator];
}
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[templateItem setTarget:itemTarget];
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
[templateItem setTag:tag];
[menu addItem:templateItem];
}
else if (tag === CPSearchFieldRecentsMenuItemTag)
switch ([item tag])
{
var j;
for (j = 0; j < countOfRecents; j++)
case CPSearchFieldRecentsTitleMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
{
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:self];
[menu addItem:rencentItem];
var itemAction = @selector(_searchFieldSearch:);
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
{
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[item setTarget:self];
[menu addItem:recentItem];
}
continue;
}
case CPSearchFieldClearRecentsMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
[item setAction:@selector(_searchFieldClearRecents:)];
[item setTarget:self];
break;
case CPSearchFieldNoRecentsMenuItemTag:
if (countOfRecents !== 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldSeparatorMenuItemTag:
item = [CPMenuItem separatorItem];
[item setEnabled:NO];
[menu addItem:item];
continue;
}
}
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
[menu addItem:item];
}
[menu setDelegate:self];
_searchMenu = menu;
}
- (void)_showMenu:(id)sender
- (void)_addSeparatorToMenu:(CPMenu)aMenu
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[aMenu addItem:separator];
}
- (void)menuWillOpen:(CPMenu)menu
{
_canResignFirstResponder = NO;
}
- (void)menuDidClose:(CPMenu)menu
{
_canResignFirstResponder = YES;
[self becomeFirstResponder];
}
- (void)_showMenu
{
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return;
@@ -576,12 +670,14 @@ var CPSearchFieldSearchImage = nil,
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
[self selectAll:nil];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
}
- (void)_sendPartialString
{
[self _sendAction:self];
[super sendAction:[self action] to:[self target]];
[_partialStringTimer invalidate];
}
- (void)_searchFieldCancel:(id)sender
@@ -593,14 +689,15 @@ var CPSearchFieldSearchImage = nil,
- (void)_searchFieldSearch:(id)sender
{
var searchString = [sender title];
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString];
[self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility];
}
@@ -608,6 +705,8 @@ var CPSearchFieldSearchImage = nil,
{
[self setRecentSearches:[CPArray array]];
[self _updateSearchMenu];
[self setStringValue:@""];
[self _updateCancelButtonVisibility];
}
- (void)_registerForAutosaveNotification
@@ -668,7 +767,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
@implementation CPSearchField (CPCoding)
@@ -690,6 +789,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
}
@@ -698,18 +798,17 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{
if (self = [super initWithCoder:coder])
{
[self _initWithFrame:[self frame]];
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template)
[self setSearchMenuTemplate:template];
[self setDelegate:self];
[self _init];
}
return self;
+53 -50
View File
@@ -82,7 +82,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)selectedTag
{
return _segments[_selectedSegment].tag;
return [_segments[_selectedSegment] tag];
}
// Specifying the number of segments
@@ -183,7 +183,7 @@ CPSegmentSwitchTrackingMomentary = 2;
selected = NO;
for (; index < _segments.length; ++index)
if (_segments[index].selected)
if ([_segments[index] selected])
if (selected)
[self setSelected:NO forSegment:index];
else
@@ -195,7 +195,7 @@ CPSegmentSwitchTrackingMomentary = 2;
var index = 0;
for (; index < _segments.length; ++index)
if (_segments[index].selected)
if ([_segments[index] selected])
[self setSelected:NO forSegment:index];
}
}
@@ -217,7 +217,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{
_segments[aSegment].width = aWidth;
[_segments[aSegment] setWidth:aWidth];
[self tileWithChangedSegment:aSegment];
}
@@ -229,7 +229,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (float)widthForSegment:(unsigned)aSegment
{
return _segments[aSegment].width;
return [_segments[aSegment] width];
}
/*!
@@ -240,9 +240,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
segment.image = anImage;
[_segments[aSegment] setImage:anImage];
[self tileWithChangedSegment:aSegment];
}
@@ -254,7 +252,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPImage)imageForSegment:(unsigned)aSegment
{
return _segments[aSegment].image;
return [_segments[aSegment] image];
}
/*!
@@ -265,9 +263,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
_segments[aSegment].label = aLabel;
[_segments[aSegment] setLabel:aLabel];
[self tileWithChangedSegment:aSegment];
}
@@ -279,7 +275,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPString)labelForSegment:(unsigned)aSegment
{
return _segments[aSegment].label;
return [_segments[aSegment] label];
}
/*!
@@ -290,7 +286,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
{
_segments[aSegment].menu = aMenu;
[_segments[aSegment] setMenu:aMenu];
}
/*!
@@ -300,7 +296,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPMenu)menuForSegment:(unsigned)aSegment
{
return _segments[aSegment].menu;
return [_segments[aSegment] menu];
}
/*!
@@ -315,10 +311,10 @@ CPSegmentSwitchTrackingMomentary = 2;
var segment = _segments[aSegment];
// If we're already in this state, bail.
if (segment.selected == isSelected)
if ([segment selected] == isSelected)
return;
segment.selected = isSelected;
[segment setSelected:isSelected];
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
@@ -331,7 +327,7 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
{
_segments[oldSelectedSegment].selected = NO;
[_segments[oldSelectedSegment] setSelected:NO];
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
@@ -352,7 +348,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isSelectedForSegment:(unsigned)aSegment
{
return _segments[aSegment].selected;
return [_segments[aSegment] selected];
}
/*!
@@ -363,6 +359,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
[_segments[aSegment] setEnabled:isEnabled];
if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled;
else
@@ -379,7 +377,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
return !(_themeStates[aSegment] & CPThemeStateDisabled)
return [_segments[aSegment] enabled];
}
/*!
@@ -389,7 +387,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
{
_segments[aSegment].tag = aTag;
[_segments[aSegment] setTag:aTag];
}
/*!
@@ -398,7 +396,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)tagForSegment:(unsigned)aSegment
{
return _segments[aSegment].tag;
return [_segments[aSegment] tag];
}
// Drawings
@@ -461,7 +459,7 @@ CPSegmentSwitchTrackingMomentary = 2;
else if (aName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy(_segments[segment].frame);
frame = CGRectCreateCopy([_segments[segment] frame]);
if (segment === 0)
{
@@ -556,8 +554,8 @@ CPSegmentSwitchTrackingMomentary = 2;
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
[contentView setText:segment.label];
[contentView setImage:segment.image];
[contentView setText:[segment label]];
[contentView setImage:[segment image]];
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
@@ -568,9 +566,9 @@ CPSegmentSwitchTrackingMomentary = 2;
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if (segment.image && segment.label)
if ([segment image] && [segment label])
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
else if (segment.image)
else if ([segment image])
[contentView setImagePosition:CPImageOnly];
if (i == count - 1)
@@ -609,27 +607,32 @@ CPSegmentSwitchTrackingMomentary = 2;
return;
var segment = _segments[aSegment],
segmentWidth = segment.width,
segmentWidth = [segment width],
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
font = [self valueForThemeAttribute:@"font" inState:themeState];
if (!segmentWidth)
{
if (segment.image && segment.label)
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
if ([segment image] && [segment label])
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
else if (segment.image)
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
else if (segment.label)
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
else
segmentWidth = 0.0;
}
var delta = segmentWidth - CGRectGetWidth(segment.frame);
var delta = segmentWidth - CGRectGetWidth([segment frame]);
if (!delta)
{
[self setNeedsLayout];
[self setNeedsDisplay:YES];
return;
}
// Update Contorl Size
var frame = [self frame];
@@ -637,15 +640,15 @@ CPSegmentSwitchTrackingMomentary = 2;
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
// Update Segment Width
segment.width = segmentWidth;
segment.frame = [self frameForSegment:aSegment];;
[segment setWidth:segmentWidth];
[segment setFrame:[self frameForSegment:aSegment]];
// Update Following Segments Widths
var index = aSegment + 1;
for (; index < _segments.length; ++index)
{
_segments[index].frame.origin.x += delta;
[_segments[index] frame].origin.x += delta;
[self drawSegmentBezel:index highlight:NO];
[self drawSegment:index highlight:NO];
@@ -698,12 +701,12 @@ CPSegmentSwitchTrackingMomentary = 2;
count = _segments.length;
while (count--)
if (CGRectContainsPoint(_segments[count].frame, aPoint))
if (CGRectContainsPoint([_segments[count] frame], aPoint))
return count;
if (_segments.length)
{
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
@@ -844,7 +847,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
for (var i = 0; i < _segments.length; i++)
{
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
[self tileWithChangedSegment:i];
}
@@ -852,7 +855,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
remainingWidth = FLOOR(difference / _segments.length);
for (var i=0; i < _segments.length; i++)
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
[self tileWithChangedSegment:0];
}
@@ -875,15 +878,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@implementation _CPSegmentItem : CPObject
{
CPImage image;
CPString label;
CPMenu menu;
BOOL selected;
BOOL enabled;
int tag;
int width;
CPImage image @accessors;
CPString label @accessors;
CPMenu menu @accessors;
BOOL selected @accessors;
BOOL enabled @accessors;
int tag @accessors;
int width @accessors;
CGRect frame;
CGRect frame @accessors;
}
- (id)init
@@ -894,8 +897,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
label = @"";
menu = nil;
selected = NO;
enabled = NO;
tag = 0;
enabled = YES;
tag = -1;
width = 0;
frame = CGRectMakeZero();
+41 -16
View File
@@ -35,12 +35,12 @@ CPHeavyShadow = 1;
var CPShadowViewLightBackgroundColor = nil,
CPShadowViewHeavyBackgroundColor = nil;
var LIGHT_LEFT_INSET = 3.0,
LIGHT_RIGHT_INSET = 3.0,
LIGHT_TOP_INSET = 3.0,
LIGHT_BOTTOM_INSET = 5.0,
HEAVY_LEFT_INSET = 7.0,
HEAVY_RIGHT_INSET = 7.0,
HEAVY_TOP_INSET = 5.0,
@@ -61,51 +61,76 @@ var LIGHT_LEFT_INSET = 3.0,
return;
var bundle = [CPBundle bundleForClass:[self class]];
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
]]];
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
]]];
}
+ (id)shadowViewEnclosingView:(CPView)aView
{
return [self shadowViewEnclosingView:aView withWeight:CPLightShadow];
}
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
{
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
[shadowView setWeight:aWeight];
var size = [shadowView frame].size,
width = size.width - [shadowView leftInset] - [shadowView rightInset],
height = size.height - [shadowView topInset] - [shadowView bottomInset],
enclosingView = [aView superview];
[shadowView setHitTests:[aView hitTests]];
[shadowView setAutoresizingMask:[aView autoresizingMask]];
[aView removeFromSuperview];
[shadowView addSubview:aView];
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
[enclosingView addSubview:shadowView];
return shadowView;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_weight = CPLightShadow;
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
[self setHitTests:NO];
}
return self;
}
@@ -113,9 +138,9 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == aWeight)
return;
_weight = aWeight;
if (_weight == CPLightShadow)
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
@@ -147,7 +172,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
}
@@ -155,7 +180,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
}
+2 -2
View File
@@ -198,7 +198,7 @@ CPCircularSlider = 1;
else if ([self isVertical])
{
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
}
else
{
@@ -320,7 +320,7 @@ CPCircularSlider = 1;
var minValue = [self minValue];
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
}
else
{
+101 -167
View File
@@ -47,16 +47,15 @@
CPTextField _saturationLabel;
CPTextField _brightnessLabel;
CPTextField _hexLabel;
CPTextField _hexValue;
#if PLATFORM(DOM)
DOMElement _redValue;
DOMElement _greenValue;
DOMElement _blueValue;
DOMElement _hueValue;
DOMElement _saturationValue;
DOMElement _brightnessValue;
DOMElement _hexValue;
#endif
CPTextField _hexValue;
CPTextField _redValue;
CPTextField _greenValue;
CPTextField _blueValue;
CPTextField _hueValue;
CPTextField _saturationValue;
CPTextField _brightnessValue;
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
@@ -86,73 +85,13 @@
[_redSlider setAction: @selector(sliderChanged:)];
[_redSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
var updateFunction = function(aDOMEvent)
{
if(isNaN(this.value))
return;
switch(this)
{
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _redSlider];
break;
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _greenSlider];
break;
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
//[self sliderChanged: _blueSlider];
break;
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
//[self sliderChanged: _hueSlider];
break;
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _saturationSlider];
break;
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _brightnessSlider];
break;
}
this.blur();
};
var keypressFunction = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == 13)
{
updateFunction(aDOMEvent);
if(aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
else if(aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
}
}
//red value input box
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
[redValue setAutoresizingMask: CPViewMinXMargin];
_redValue = document.createElement("input");
_redValue.style.width = "40px";
_redValue.style.backgroundColor = "transparent";
_redValue.style.border = "1px solid black";
_redValue.style.color = "black";
_redValue.style.position = "absolute";
_redValue.style.top = "0px";
_redValue.style.left = "0px";
_redValue.onchange = updateFunction;
redValue._DOMElement.appendChild(_redValue);
[_contentView addSubview: redValue];
#endif
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
[_greenLabel setStringValue: "G"];
@@ -165,17 +104,13 @@
[_greenSlider setAction: @selector(sliderChanged:)];
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//green value input box
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
[greenValue setAutoresizingMask: CPViewMinXMargin];
_greenValue = _redValue.cloneNode(false);
_greenValue.onchange = updateFunction;
greenValue._DOMElement.appendChild(_greenValue);
[_contentView addSubview: greenValue];
#endif
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
[_blueLabel setStringValue: "B"];
@@ -188,17 +123,14 @@
[_blueSlider setAction: @selector(sliderChanged:)];
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//blue value input box
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
[blueValue setAutoresizingMask: CPViewMinXMargin];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
[_blueValue setDelegate: self];
[_contentView addSubview: _blueValue];
_blueValue = _redValue.cloneNode(false);
_blueValue.onchange = updateFunction;
blueValue._DOMElement.appendChild(_blueValue);
[_contentView addSubview: blueValue];
#endif
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
[_hsbLabel setTextColor:[CPColor blackColor]];
@@ -214,17 +146,14 @@
[_hueSlider setAction: @selector(sliderChanged:)];
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//red value input box
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
[hueValue setAutoresizingMask: CPViewMinXMargin];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
_hueValue = _redValue.cloneNode(false);
_hueValue.onchange = updateFunction;
hueValue._DOMElement.appendChild(_hueValue);
[_contentView addSubview: hueValue];
#endif
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
@@ -236,17 +165,14 @@
[_saturationSlider setAction: @selector(sliderChanged:)];
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//green value input box
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
[saturationValue setAutoresizingMask: CPViewMinXMargin];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
_saturationValue = _redValue.cloneNode(false);
_saturationValue.onchange = updateFunction;
saturationValue._DOMElement.appendChild(_saturationValue);
[_contentView addSubview: saturationValue];
#endif
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
@@ -258,51 +184,24 @@
[_brightnessSlider setAction: @selector(sliderChanged:)];
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
#if PLATFORM(DOM)
//blue value input box
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
[_brightnessValue setDelegate: self];
[_contentView addSubview: _brightnessValue];
_brightnessValue = _redValue.cloneNode(false);
_brightnessValue.onchange = updateFunction;
brightnessValue._DOMElement.appendChild(_brightnessValue);
[_contentView addSubview: brightnessValue];
#endif
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
[_hexLabel setStringValue: "Hex"];
[_hexLabel setTextColor:[CPColor blackColor]];
#if PLATFORM(DOM)
//hex input box
_hexValue = _redValue.cloneNode(false);
_hexValue.style.top = "228px";
_hexValue.style.width = "80px";
_hexValue.style.left = "35px";
_hexValue.onkeypress = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == 13)
{
var newColor = [CPColor colorWithHexString: this.value];
if(newColor)
{
[self setColor: newColor];
[[self colorPanel] setColor: newColor];
}
if(aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
else if(aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
this.blur();
}
};
_contentView._DOMElement.appendChild(_hexValue);
#endif
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
[_contentView addSubview: _hexValue];
[_contentView addSubview: _rgbLabel];
[_contentView addSubview: _redLabel];
@@ -394,9 +293,7 @@
- (void)updateHex:(CPColor)aColor
{
#if PLATFORM(DOM)
_hexValue.value = [aColor hexString];
#endif
[_hexValue setStringValue:[aColor hexString]];
}
- (void)updateRGBSliders:(CPColor)aColor
@@ -410,15 +307,13 @@
- (void)updateLabels
{
#if PLATFORM(DOM)
_hueValue.value = ROUND([_hueSlider floatValue]);
_saturationValue.value = ROUND([_saturationSlider floatValue]);
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
_redValue.value = ROUND([_redSlider floatValue] * 255);
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
#endif
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
}
- (CPImage)provideNewButtonImage
@@ -431,4 +326,43 @@
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
}
- (void)controlTextDidEndEditing:(CPNotification)aNotification
{
var field = [aNotification object],
value = [[field stringValue] stringByTrimmingWhitespace];
if (field === _hexValue) {
var newColor = [CPColor colorWithHexString: value];
if (newColor) {
[self setColor: newColor];
[[self colorPanel] setColor: newColor];
}
} else {
switch(field) {
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _redSlider];
break;
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _greenSlider];
break;
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _blueSlider];
break;
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
[self sliderChanged: _hueSlider];
break;
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
[self sliderChanged: _saturationSlider];
break;
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
[self sliderChanged: _brightnessSlider];
break;
}
}
}
@end
+39 -11
View File
@@ -47,6 +47,7 @@ var CPSplitViewHorizontalImage = nil,
int _currentDivider;
float _initialOffset;
float _preCollapsePosition;
CPString _originComponent;
CPString _sizeComponent;
@@ -60,6 +61,17 @@ var CPSplitViewHorizontalImage = nil,
CPArray _buttonBars;
}
+ (CPString)themeClass
{
return @"splitview";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[10.0, 1.0]
forKeys:[@"divider-thickness", @"pane-divider-thickness"]];
}
/*
@ignore
*/
@@ -90,7 +102,7 @@ var CPSplitViewHorizontalImage = nil,
- (float)dividerThickness
{
return _isPaneSplitter ? 1.0 : 10.0;
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
}
- (BOOL)isVertical
@@ -152,7 +164,7 @@ var CPSplitViewHorizontalImage = nil,
_isPaneSplitter = shouldBePaneSplitter;
if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]
[self _setupDOMDivider];
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
@@ -293,7 +305,7 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
return CGRectContainsPoint(effectiveRect, aPoint) ||
return CGRectContainsPoint(effectiveRect, aPoint) ||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
}
@@ -358,14 +370,14 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:minPosition ofDividerAtIndex:i];
}
else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i+1]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:maxPosition ofDividerAtIndex:i];
}
@@ -444,11 +456,19 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{
var frame = [_subviews[i] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
size = frame.size[_sizeComponent],
startPosition = frame.origin[_originComponent] + size,
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor];
if (size === 0)
canGrow = YES; // Subview is collapsed.
else if (!canShrink &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate splitView:self canCollapseSubview:_subviews[i]])
canShrink = YES; // Subview is collapsible.
if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink)
@@ -531,10 +551,18 @@ var CPSplitViewHorizontalImage = nil,
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
_preCollapsePosition = 0;
var preSize = frameA.size[_sizeComponent];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
[_subviews[dividerIndex] setFrame:frameA];
preSize = frameB.size[_sizeComponent];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB];
@@ -641,14 +669,14 @@ var CPSplitViewHorizontalImage = nil,
/*!
Set the button bar who's resize control should act as a control for this splitview.
Each divider can have at most one button bar assigned to it, and that button bar must be
Each divider can have at most one button bar assigned to it, and that button bar must be
a subview of one of the split view's subviews.
Calling this method with nil as the button bar will remove any currently assigned button bar
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
should usually call this method after adding all the desired subviews to the split view.
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
parameters of the button bar, and will override any currently set values.
*/
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
@@ -669,7 +697,7 @@ var CPSplitViewHorizontalImage = nil,
}
if (view !== self)
[CPException raise:CPInvalidArgumentException
[CPException raise:CPInvalidArgumentException
reason:@"CPSplitView button bar must be a subview of the split view."];
var viewIndex = [[self subviews] indexOfObject:subview];
@@ -677,7 +705,7 @@ var CPSplitViewHorizontalImage = nil,
[aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar;
_buttonBars[dividerIndex] = aButtonBar;
}
- (void)_postNotificationWillResize
@@ -714,7 +742,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
+8
View File
@@ -27,6 +27,14 @@
@implementation CPString (CPStringDrawing)
/*!
Returns a dictionary with the items "ascender", "descender", "lineHeight"
*/
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
return [CPPlatformString metricsOfFont:aFont];
}
/*!
Returns the string
*/
+113 -107
View File
@@ -63,20 +63,20 @@ var CPTabViewBezelBorderLeftImage = nil,
var LEFT_INSET = 7.0,
RIGHT_INSET = 7.0;
var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewShouldSelectTabViewItemSelector = 2,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*!
/*!
@ingroup appkit
@class CPTabView
This class represents a view that has multiple subviews (CPTabViewItem) presented as individual tabs.
Only one CPTabViewItem is shown at a time, and other CPTabViewItems can be made visible
(one at a time) by clicking on the CPTabViewItem's tab at the top of the tab view.
THe currently selected CPTabViewItem is the view that is displayed.
*/
@implementation CPTabView : CPView
@@ -84,15 +84,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPView _labelsView;
CPView _backgroundView;
CPView _separatorView;
CPView _auxiliaryView;
CPView _contentView;
CPArray _tabViewItems;
CPTabViewItem _selectedTabViewItem;
CPTabViewType _tabViewType;
id _delegate;
unsigned _delegateSelectors;
}
@@ -104,20 +104,20 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (self != CPTabView)
return;
var bundle = [CPBundle bundleForClass:self],
emptyImage = [[CPImage alloc] initByReferencingFile:@"" size:CGSizeMake(7.0, 0.0)],
backgroundImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBackgroundCenter.png"] size:CGSizeMake(1.0, 1.0)],
bezelBorderLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderLeft.png"] size:CGSizeMake(7.0, 1.0)],
bezerBorderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorder.png"] size:CGSizeMake(1.0, 1.0)],
bezelBorderRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderRight.png"] size:CGSizeMake(7.0, 1.0)];
CPTabViewBezelBorderBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
emptyImage,
emptyImage,
emptyImage,
emptyImage,
emptyImage,
bezelBorderLeftImage,
@@ -128,7 +128,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
bezerBorderImage,
bezelBorderRightImage
]]];
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
}
@@ -143,13 +143,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_tabViewType = CPTopTabsBezelBorder;
_tabViewItems = [];
}
return self;
}
@@ -157,7 +157,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (_tabViewType != CPTopTabsBezelBorder || _labelsView)
return;
[self _createBezelBorder];
[self layoutSubviews];
}
@@ -166,7 +166,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
- (void)_createBezelBorder
{
var bounds = [self bounds];
_labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)];
[_labelsView setTabView:self];
@@ -174,19 +174,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[self addSubview:_labelsView];
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[_backgroundView setBackgroundColor:CPTabViewBezelBorderBackgroundColor];
[_backgroundView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_backgroundView];
_separatorView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[_separatorView setBackgroundColor:[[self class] bezelBorderColor]];
[_separatorView setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin];
[self addSubview:_separatorView];
}
@@ -200,21 +200,21 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
var backgroundRect = [self bounds],
labelsViewHeight = [_CPTabLabelsView height];
backgroundRect.origin.y += labelsViewHeight;
backgroundRect.size.height -= labelsViewHeight;
[_backgroundView setFrame:backgroundRect];
var auxiliaryViewHeight = 5.0;
if (_auxiliaryView)
{
auxiliaryViewHeight = CGRectGetHeight([_auxiliaryView frame]);
[_auxiliaryView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, auxiliaryViewHeight)];
}
[_separatorView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight + auxiliaryViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, 1.0)];
}
@@ -240,15 +240,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
*/
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
{
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
if (!_labelsView)
[self _createBezelBorder];
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
@@ -265,11 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var index = [self indexOfTabViewItem:aTabViewItem];
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
@@ -292,7 +292,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
var index = 0,
count = [_tabViewItems count];
for (; index < count; ++index)
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
return index;
@@ -332,7 +332,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
- (void)selectFirstTabViewItem:(id)aSender
{
var count = [_tabViewItems count];
if (count)
[self selectTabViewItemAtIndex:0];
}
@@ -344,7 +344,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
- (void)selectLastTabViewItem:(id)aSender
{
var count = [_tabViewItems count];
if (count)
[self selectTabViewItemAtIndex:count - 1];
}
@@ -357,10 +357,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (!_selectedTabViewItem)
return;
var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
[self selectTabViewItemAtIndex:index + 1 % count];
}
@@ -372,10 +372,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (!_selectedTabViewItem)
return;
var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
}
@@ -387,7 +387,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
@@ -395,29 +395,35 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
_selectedTabViewItem._tabState = CPBackgroundTab;
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
[_contentView removeFromSuperview];
[_auxiliaryView removeFromSuperview];
}
_selectedTabViewItem = aTabViewItem;
_selectedTabViewItem._tabState = CPSelectedTab;
_contentView = [_selectedTabViewItem view];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_contentView];
if (_auxiliaryView)
_selectedTabViewItem._tabState = CPSelectedTab;
var _previousContentView = _contentView;
_contentView = [_selectedTabViewItem view];
if (_previousContentView !== _contentView)
{
[_previousContentView removeFromSuperview];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_contentView];
}
var _previousAuxiliaryView = _auxiliaryView;
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
if (_previousAuxiliaryView !== _auxiliaryView)
{
[_previousAuxiliaryView removeFromSuperview];
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_auxiliaryView];
}
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
[self layoutSubviews];
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
}
@@ -439,7 +445,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
return _selectedTabViewItem;
}
//
//
/*!
Sets the tab view type.
@param aTabViewType the view type
@@ -448,19 +454,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (_tabViewType == aTabViewType)
return;
_tabViewType = aTabViewType;
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_labelsView removeFromSuperview];
else if (![_labelsView superview])
else if (_labelsView && ![_labelsView superview])
[self addSubview:_labelsView];
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_backgroundView removeFromSuperview];
else if (![_backgroundView superview])
else if (_backgroundView && ![_backgroundView superview])
[self addSubview:_backgroundView];
[self layoutSubviews];
}
@@ -479,7 +485,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
- (CGRect)contentRect
{
var contentRect = CGRectMakeCopy([self bounds]);
if (_tabViewType == CPTopTabsBezelBorder)
{
var labelsViewHeight = [_CPTabLabelsView height],
@@ -488,7 +494,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
contentRect.origin.y += labelsViewHeight + auxiliaryViewHeight + separatorViewHeight;
contentRect.size.height -= labelsViewHeight + auxiliaryViewHeight + separatorViewHeight * 2.0; // 2 for the bottom border as well.
contentRect.origin.x += LEFT_INSET;
contentRect.size.width -= LEFT_INSET + RIGHT_INSET;
}
@@ -512,9 +518,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
if (_delegate == aDelegate)
return;
_delegate = aDelegate;
_delegateSelectors = 0;
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
@@ -527,7 +533,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
}
//
@@ -536,7 +542,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
{
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
if (tabViewItem)
[self selectTabViewItem:tabViewItem];
}
@@ -556,18 +562,18 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
_tabViewItems = [];
// FIXME: this is somewhat hacky
[self _createBezelBorder];
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
for (var i = 0; items && i < items.length; i++)
[self insertTabViewItem:items[i] atIndex:i];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
}
@@ -580,12 +586,12 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
_subviews = [];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
@@ -609,7 +615,7 @@ var _CPTabLabelsViewBackgroundColor = nil,
return;
var bundle = [CPBundle bundleForClass:self];
_CPTabLabelsViewBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewLeft.png"] size:CGSizeMake(12.0, 26.0)],
@@ -626,16 +632,16 @@ var _CPTabLabelsViewBackgroundColor = nil,
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_tabLabels = [];
[self setBackgroundColor:_CPTabLabelsViewBackgroundColor];
[self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)];
}
return self;
}
@@ -652,24 +658,24 @@ var _CPTabLabelsViewBackgroundColor = nil,
- (void)tabView:(CPTabView)aTabView didAddTabViewItem:(CPTabViewItem)aTabViewItem
{
var label = [[_CPTabLabel alloc] initWithFrame:CGRectMakeZero()];
[label setTabViewItem:aTabViewItem];
_tabLabels.push(label);
[self addSubview:label];
[self layoutSubviews];
}
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
{
var label = _tabLabels[index];
[_tabLabels removeObjectAtIndex:index];
[label removeFromSuperview];
[self layoutSubviews];
}
@@ -682,11 +688,11 @@ var _CPTabLabelsViewBackgroundColor = nil,
{
var index = 0,
count = _tabLabels.length;
for (; index < count; ++index)
{
var label = _tabLabels[index];
if (CGRectContainsPoint([label frame], aPoint))
return [label tabViewItem];
}
@@ -700,14 +706,14 @@ var _CPTabLabelsViewBackgroundColor = nil,
count = _tabLabels.length,
width = (_CGRectGetWidth([self bounds]) - (count - 1) * _CPTabLabelsViewInsideMargin - 2 * _CPTabLabelsViewOutsideMargin) / count,
x = _CPTabLabelsViewOutsideMargin;
for (; index < count; ++index)
{
var label = _tabLabels[index],
frame = _CGRectMake(x, 8.0, width, 18.0);
[label setFrame:frame];
x = _CGRectGetMaxX(frame) + _CPTabLabelsViewInsideMargin;
}
}
@@ -716,9 +722,9 @@ var _CPTabLabelsViewBackgroundColor = nil,
{
if (CGSizeEqualToSize([self frame].size, aSize))
return;
[super setFrameSize:aSize];
[self layoutSubviews];
}
@@ -740,14 +746,14 @@ var _CPTabLabelBackgroundColor = nil,
return;
var bundle = [CPBundle bundleForClass:self];
_CPTabLabelBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundLeft.png"] size:CGSizeMake(6.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundCenter.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundRight.png"] size:CGSizeMake(6.0, 18.0)]
] isVertical:NO]];
_CPTabLabelSelectedBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedLeft.png"] size:CGSizeMake(3.0, 18.0)],
@@ -759,21 +765,21 @@ var _CPTabLabelBackgroundColor = nil,
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
{
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_labelField setAlignment:CPCenterTextAlignment];
[_labelField setFrame:CGRectMake(5.0, 0.0, CGRectGetWidth(aFrame) - 10.0, 20.0)];
[_labelField setAutoresizingMask:CPViewWidthSizable];
[_labelField setFont:[CPFont boldSystemFontOfSize:11.0]];
[self addSubview:_labelField];
[self setTabState:CPBackgroundTab];
}
return self;
}
@@ -785,7 +791,7 @@ var _CPTabLabelBackgroundColor = nil,
- (void)setTabViewItem:(CPTabViewItem)aTabViewItem
{
_tabViewItem = aTabViewItem;
[self update];
}
+25 -26
View File
@@ -78,18 +78,7 @@ CPTableColumnUserResizingMask = 1 << 1;
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header];
var textDataView = [CPTextField new];
[textDataView setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]
forThemeAttribute:"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelectedDataView];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateSelectedDataView];
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[textDataView setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset"];
[self setDataView:textDataView];
[self setDataView:[CPTextField new]];
}
return self;
@@ -237,12 +226,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
This method set's the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@@ -259,6 +248,8 @@ CPTableColumnUserResizingMask = 1 << 1;
if (_dataView)
_dataViewData[[_dataView UID]] = nil;
[aView setThemeState:CPThemeStateTableDataView];
_dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
}
@@ -298,6 +289,9 @@ CPTableColumnUserResizingMask = 1 << 1;
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView;
}
@@ -356,9 +350,9 @@ CPTableColumnUserResizingMask = 1 << 1;
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
}
@@ -413,7 +407,8 @@ CPTableColumnUserResizingMask = 1 << 1;
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
bindingInfo = [bindingsDictionary objectForKey:bindingName]._info,
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf("."),
@@ -444,6 +439,8 @@ CPTableColumnUserResizingMask = 1 << 1;
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
}
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
[aDataView setValue:value forKey:bindingPath];
}
@@ -468,9 +465,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey";
CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey";
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
@implementation CPTableColumn (CPCoding)
@@ -491,9 +488,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenkey];
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
}
@@ -512,8 +510,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenkey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
}
+114 -84
View File
@@ -23,53 +23,60 @@
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
@implementation _CPTableColumnHeaderView : CPView
{
_CPImageAndTextView _textField;
}
+ (CPString)themeClass
{
return @"columnHeader";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]];
}
- (void)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self _init];
}
return self;
}
- (void)_init
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:
CGRectMake(5.0, 0.0, CGRectGetWidth([self bounds]) - 10.0, CGRectGetHeight([self bounds]))];
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField];
}
- (void)layoutSubviews
{
var themeState = [self themeState];
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 23.0))]];
else if (themeState & CPThemeStateSelected)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 23.0))]];
else if (themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 23.0))]];
else
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
var inset = [self currentValueForThemeAttribute:@"text-inset"],
bounds = [self bounds];
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
}
- (void)setStringValue:(CPString)string
@@ -97,11 +104,6 @@
[_textField setFont:aFont];
}
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage
{
if (anImage)
@@ -149,34 +151,47 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
@implementation CPTableHeaderView : CPView
{
CPPoint _mouseDownLocation;
CPPoint _previousTrackingLocation;
CGPoint _mouseDownLocation;
CGPoint _previousTrackingLocation;
int _activeColumn;
int _pressedColumn;
BOOL _isResizing;
BOOL _isDragging;
BOOL _isTrackingColumn;
BOOL _drawsColumnLines;
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
}
+ (CPString)themeClass
{
return @"tableHeaderRow";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
forKeys:[@"background-color", @"divider-color"]];
}
- (void)_init
{
_mouseDownLocation = CPPointMakeZero();
_previousTrackingLocation = CPPointMakeZero();
_mouseDownLocation = _CGPointMakeZero();
_previousTrackingLocation = _CGPointMakeZero();
_activeColumn = -1;
_pressedColumn = -1;
_isResizing = NO;
_isDragging = NO;
_isTrackingColumn = NO;
_drawsColumnLines = YES;
_columnOldWidth = 0.0;
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -199,23 +214,33 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
var headerRect = [self bounds],
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = CPRectGetMinX(columnRect);
headerRect.size.width = CPRectGetWidth(columnRect);
headerRect.origin.x = _CGRectGetMinX(columnRect);
headerRect.size.width = _CGRectGetWidth(columnRect);
return headerRect;
}
- (void)setDrawsColumnLines:(BOOL)aFlag
{
_drawsColumnLines = aFlag;
}
- (BOOL)drawsColumnLines
{
return _drawsColumnLines;
}
- (CGRect)_cursorRectForColumn:(int)column
{
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return CGRectMakeZero();
return _CGRectMakeZero();
var rect = [self headerRectOfColumn:column];
rect.origin.x = CGRectGetMaxX(rect) - 5;
rect.origin.x = _CGRectGetMaxX(rect) - 5;
rect.size.width = 20;
return rect;
return rect;
}
- (void)_setPressedColumn:(CPInteger)column
@@ -224,7 +249,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
{
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStateHighlighted];
}
}
if (column != -1)
{
@@ -249,7 +274,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
currentLocation.x -= 5.0;
var columnIndex = [self columnAtPoint:currentLocation],
shouldResize = [self shouldResizeTableColumn:columnIndex at:CPPointMake(currentLocation.x + 5.0, currentLocation.y)];
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
if (type === CPLeftMouseUp)
{
@@ -293,7 +318,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[self continueResizingTableColumn:_activeColumn at:currentLocation];
else
{
if (_activeColumn === columnIndex && CPRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
{
if (_isTrackingColumn && _pressedColumn !== -1)
{
@@ -311,24 +336,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:aColumnIndex];
}
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
{
var columnRect = [self headerRectOfColumn:aColumnIndex],
offset = CPPointMakeZero(),
offset = _CGPointMakeZero(),
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
viewLocation = CPPointMakeZero();
viewLocation = _CGPointMakeZero();
viewLocation.x = ( CPRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = CPRectGetMinY(columnRect) + offset.y;
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
[self dragView:view at:viewLocation offset:CPSizeMakeZero() event:[CPApp currentEvent]
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
return NO;
@@ -337,24 +362,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return YES;
}
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return _isTrackingColumn && _activeColumn === aColumnIndex &&
CPRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
return _isTrackingColumn && _activeColumn === aColumnIndex &&
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
}
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:CPNotFound];
[self _updateResizeCursor:[CPApp currentEvent]];
}
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
}
- (CPRect)_headerRectOfLastVisibleColumn
- (CGRect)_headerRectOfLastVisibleColumn
{
var tableColumns = [_tableView tableColumns],
columnIndex = [tableColumns count];
@@ -370,11 +395,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return nil;
}
- (void)_constrainDragView:(CPView)theDragView at:(CPPoint)aPoint
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
{
var tableColumns = [_tableView tableColumns],
lastColumnRect = [self _headerRectOfLastVisibleColumn];
activeColumnRect = [self headerRectOfColumn:_activeColumn];
lastColumnRect = [self _headerRectOfLastVisibleColumn],
activeColumnRect = [self headerRectOfColumn:_activeColumn],
dragWindow = [theDragView window],
frame = [dragWindow frame];
@@ -384,10 +409,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
frame.origin = [self convertPoint:frame.origin fromView:nil];
// This effectively clamps the value between the minimum and maximum
frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect)));
frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
// Make sure the column cannot move vertically
frame.origin.y = CPRectGetMinY(lastColumnRect);
frame.origin.y = _CGRectGetMinY(lastColumnRect);
// Convert the calculated origin back to the window coordinate system
frame.origin = [self convertPoint:frame.origin toView:nil];
@@ -402,21 +427,21 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
_activeColumn = aToIndex;
_pressedColumn = _activeColumn;
[_tableView _setDraggedColumn:_activeColumn];
}
- (void)draggedView:(CPView)aView beganAt:(CPPoint)aPoint
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
{
_isDragging = YES;
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:YES];
[_tableView _setDraggedColumn:_activeColumn];
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
[[column headerView] setHidden:YES];
[_tableView _setDraggedColumn:column];
[self setNeedsDisplay:YES];
}
- (void)draggedView:(CPView)aView movedTo:(CPPoint)aPoint
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
{
[self _constrainDragView:aView at:aPoint];
@@ -426,9 +451,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
var hoverPoint = CGPointCreateCopy(aPoint);
if (aPoint.x < _previousTrackingLocation.x)
hoverPoint = CGPointMake(CGRectGetMinX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
else if (aPoint.x > _previousTrackingLocation.x)
hoverPoint = CGPointMake(CGRectGetMaxX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
// Convert the hover point from the global coordinate system to windows' coordinate system
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
@@ -440,7 +465,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
if (hoveredColumn !== -1)
{
var columnRect = [self headerRectOfColumn:hoveredColumn],
columnCenterPoint = [self convertPoint:CGPointMake(CGRectGetMidX(columnRect), CGRectGetMidY(columnRect)) fromView:self];
columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
@@ -455,14 +480,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
_isDragging = NO;
_isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
[_tableView _setDraggedColumn:-1];
[_tableView _setDraggedColumn:nil];
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
[self stopTrackingTableColumn:_activeColumn at:aLocation];
[self setNeedsDisplay:YES];
}
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if (_isResizing)
return YES;
@@ -470,10 +495,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
if (_isTrackingColumn)
return NO;
return [_tableView allowsColumnResizing] && CPRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
}
- (void)startResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
_isResizing = YES;
@@ -483,7 +508,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[_tableView setDisableAutomaticResizing:YES];
}
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
@@ -503,7 +528,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
}
}
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
@@ -522,11 +547,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return;
}
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation];
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width];
@@ -543,7 +568,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
}
- (void)mouseEntered:(CPEvent)theEvent
{
{
[self _updateResizeCursor:theEvent];
}
@@ -561,16 +586,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)layoutSubviews
{
var tableColumns = [_tableView tableColumns],
count = [tableColumns count];
count = [tableColumns count];
for (var i = 0; i < count; i++)
for (var i = 0; i < count; i++)
{
var column = [tableColumns objectAtIndex:i],
headerView = [column headerView];
var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5;
if (i > 0)
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
@@ -581,11 +606,13 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
if([headerView superview] != self)
[self addSubview:headerView];
}
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
}
- (void)drawRect:(CGRect)aRect
{
if (!_tableView)
if (!_tableView || ![self drawsColumnLines])
return;
var context = [[CPGraphicsContext currentContext] graphicsPort],
@@ -597,7 +624,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [_tableView gridColor]);
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
@@ -612,25 +639,26 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = CGRectGetMaxX(columnToStroke);
columnMaxX = _CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
}
CGContextClosePath(context);
CGContextStrokePath(context);
if (_isDragging)
/*if (_isDragging)
{
CGContextSetFillColor(context, [CPColor grayColor]);
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
}
}*/
}
@end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
@implementation CPTableHeaderView (CPCoding)
@@ -640,6 +668,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{
[self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
}
return self;
@@ -649,6 +678,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
}
@end
+400 -294
View File
File diff suppressed because it is too large Load Diff
+4 -12
View File
@@ -22,19 +22,11 @@
@import "CPView.j"
CPTabCharacter = "\u0009";
CPFormFeedCharacter = "\u000c";
CPNewlineCharacter = "\u000a";
CPCarriageReturnCharacter = "\u000d";
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
CPNewlineCharacter = "\u000a";
CPFormFeedCharacter = "\u000c";
CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
@implementation CPText : CPView
{
}
@end
+104 -76
View File
@@ -49,7 +49,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil;
#endif
var CPSecureTextFieldCharacter = "\u2022";
@@ -82,13 +82,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
BOOL _isSecure;
BOOL _drawsBackground;
CPColor _textFieldBackgroundColor;
id _placeholderString;
id _delegate;
CPString _textDidChangeValue;
// NS-style Display Properties
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
CPTextFieldHandleBlur = function(anEvent)
{
{
CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
}
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
{
if ([self isSecure])
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
}
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
}
else
{
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
}
return CPTextFieldDOMInputElement;
}
#endif
@@ -262,18 +262,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
}
return self;
}
#pragma mark Controlling Editability and Selectability
/*!
Sets whether or not the receiver text field can be edited
/*!
Sets whether or not the receiver text field can be edited. If NO, any
ongoing edit is ended.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
if(shouldBeEditable)
_isSelectable = YES;
// We only allow first responder status if the field is editable and enabled.
if (!shouldBeEditable && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
}
/*!
@@ -284,6 +295,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _isEditable;
}
/*!
Sets whether the field reacts to events. If NO, any ongoing edit is
ended.
*/
- (void)setEnabled:(BOOL)shouldBeEnabled
{
[super setEnabled:shouldBeEnabled];
// We only allow first responder status if the field is editable and enabled.
if (!shouldBeEnabled && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
}
/*!
Sets whether the field's text is selectable by the user.
@param aFlag \c YES makes the text selectable
@@ -346,7 +370,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
{
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
if (shouldBeRounded)
[self setThemeState:CPTextFieldStateRounded];
else
@@ -392,9 +416,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_drawsBackground == shouldDrawBackground)
return;
_drawsBackground = shouldDrawBackground;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -415,9 +439,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_textFieldBackgroundColor == aColor)
return;
_textFieldBackgroundColor = aColor;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -480,24 +504,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_DOMElement.appendChild(element);
window.setTimeout(function()
{
window.setTimeout(function()
{
element.focus();
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
CPTextFieldInputOwner = self;
}, 0.0);
element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES;
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
@@ -523,10 +547,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldInputResigning = YES;
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO;
@@ -536,14 +560,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldInputIsActive = NO;
if (document.attachEvent)
{
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
}
#endif
//post CPControlTextDidEndEditingNotification
@@ -580,7 +604,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
@@ -599,7 +623,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent)
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil
CPTextFieldCachedDragFunction = nil;
@@ -709,7 +733,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
#if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
@@ -737,7 +761,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_placeholderString === aStringValue)
return;
_placeholderString = aStringValue;
// Only update things if we need to show the placeholder
@@ -758,17 +782,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*!
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
receiver to perfectly fit the current text in stringValue in the current font, and respecting
the current theme values for content-inset, min-size, and max-size.
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
change the width of the text field. You can use setFrameSize: with the current height to set the
width, and you can get the size of a string with [CPString sizeWithFont:].
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
change the width of the text field. You can use setFrameSize: with the current height to set the
width, and you can get the size of a string with [CPString sizeWithFont:].
The logic behind this decision is that most of the time you do not know what content will be placed
in an editable text field, so you want to just choose a fixed width and leave it at that size.
in an editable text field, so you want to just choose a fixed width and leave it at that size.
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
useful for making the textfield an appropriate height.
*/
@@ -802,16 +826,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
#if PLATFORM(DOM)
var element = [self _inputElement];
if (([self isEditable] || [self isSelectable]))
{
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else
{
[[self window] makeFirstResponder:self];
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
window.setTimeout(function() {[self selectText:sender];}, 0);
}
}
#endif
}
@@ -870,14 +891,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances
try
try
{
var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
@@ -889,8 +910,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
}
catch (e)
{
// fall through to the return
}
@@ -905,7 +926,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var inputElement = [self _inputElement];
try
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
@@ -918,7 +939,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
@@ -953,7 +974,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setDelegate:(id)aDelegate
{
var defaultCenter = [CPNotificationCenter defaultCenter];
//unsubscribe the existing delegate if it exists
if (_delegate)
{
@@ -963,24 +984,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
}
_delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
[defaultCenter
addObserver:_delegate
selector:@selector(controlTextDidBeginEditing:)
name:CPControlTextDidBeginEditingNotification
object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
[defaultCenter
addObserver:_delegate
selector:@selector(controlTextDidChange:)
name:CPControlTextDidChangeNotification
object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
[defaultCenter
addObserver:_delegate
@@ -1011,15 +1032,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
if (!contentInset)
return bounds;
bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds;
}
@@ -1029,12 +1050,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (_CGInsetIsEmpty(bezelInset))
return bounds;
bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right;
bounds.size.height -= bezelInset.top + bezelInset.bottom;
return bounds;
}
@@ -1042,10 +1063,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -1056,19 +1077,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
else
{
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
//[view setImagePosition:CPNoImage];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
@@ -1077,10 +1098,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"];
@@ -1090,7 +1111,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
var string = "";
if ([self hasThemeState:CPTextFieldStatePlaceholder])
string = [self placeholderString];
else
@@ -1148,6 +1169,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
@@ -1161,7 +1183,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
@@ -1171,9 +1193,12 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
}
return self;
}
@@ -1184,14 +1209,17 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
}
+180 -20
View File
@@ -24,8 +24,9 @@
@import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeDefaultTheme = nil;
var CPThemesByName = { },
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*!
@@ -48,6 +49,27 @@ var CPThemesByName = { },
return CPThemeDefaultTheme;
}
/*!
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
will be used.
*/
+ (void)setDefaultHudTheme:(CPTheme)aTheme
{
CPThemeDefaultHudTheme = aTheme;
}
/*!
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
style mask. The default is theme with the name of the default theme with -HUD appended
at the end.
*/
+ (CPTheme)defaultHudTheme
{
if (!CPThemeDefaultHudTheme)
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
return CPThemeDefaultHudTheme;
}
+ (CPTheme)themeNamed:(CPString)aName
{
return CPThemesByName[aName];
@@ -73,9 +95,105 @@ var CPThemesByName = { },
return _name;
}
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
/*!
Returns an array of names of themed classes defined in this theme, as found in its
ThemeDescriptors.j file.
NOTE: The names are not class names (such as "CPButton"), but the names returned
by the class' +themeClass method. For example, the name for CPCheckBox is "check-box",
as defined in CPCheckBox::themeClass.
*/
- (CPArray)classNames
{
var attributes = [_attributes objectForKey:aClass];
return [_attributes allKeys];
}
/*!
Returns a dictionary of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
are instances of _CPThemeAttribute.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aClass The themed class whose attributes you want to retrieve
@return A dictionary of attributes or nil
*/
- (CPDictionary)attributesForClass:(id)aClass
{
if (!aClass)
return nil;
var className = nil;
if ([aClass isKindOfClass:[CPString class]])
{
// See if it is a class name
var theClass = CPClassFromString(aClass);
if (theClass)
aClass = theClass;
else
className = aClass;
}
if (!className)
{
if ([aClass isKindOfClass:[CPView class]])
{
if ([aClass respondsToSelector:@selector(themeClass)])
className = [aClass themeClass];
else
return nil;
}
else
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
}
return [_attributes objectForKey:className];
}
/*!
Returns an array of names of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file.
The \c aClass parameter can be one of the following:
- A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
of CPView.
- A class name, for example "CPCheckBox".
- A themed class name, for example "check-box".
If \c aClass does not refer to a themed class in this theme, nil is returned.
@param aClass The themed class whose attributes you want to retrieve
@return An array of attribute names or nil
*/
- (CPDictionary)attributeNamesForClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
if (attributes)
return [attributes allKeys];
else
return [CPArray array];
}
/*!
Returns a theme attribute defined for the given class, as found in the
theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute you want to retrieve
@param aClass The themed class in which to look for the attribute
@return An instance of _CPThemeAttribute or nil
*/
- (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
if (!attributes)
return nil;
@@ -83,6 +201,47 @@ var CPThemesByName = { },
return [attributes objectForKey:aName];
}
/*!
Returns the value for a theme attribute in its normal state, as defined for the given class
in the theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
{
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
}
/*!
Returns the value for a theme attribute in a given state, as defined for the given class
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
opposed to a single view's current theme state.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aState The state qualifier for the attribute
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
{
var attribute = [self attributeWithName:aName forClass:aClass];
if (!attribute)
return nil;
return [attribute valueForState:aState];
}
- (void)takeThemeFromObject:(id)anObject
{
var attributes = [anObject _themeAttributeDictionary],
@@ -242,7 +401,8 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected");
CPThemeStateSelectedDataView = CPThemeState("selectedDataView");
CPThemeStateTableDataView = CPThemeState("tableDataView");
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
CPThemeStateBezeled = CPThemeState("bezeled");
CPThemeStateBordered = CPThemeState("bordered");
CPThemeStateEditable = CPThemeState("editable");
@@ -255,10 +415,10 @@ CPThemeStateCircular = CPThemeState("circular");
{
CPString _name;
id _defaultValue;
CPDictionary _values;
CPDictionary _values @accessors(readonly, getter=values);
JSObject _cache;
CPThemeAttribute _parentAttribute;
_CPThemeAttribute _parentAttribute;
}
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
@@ -379,7 +539,7 @@ CPThemeStateCircular = CPThemeState("circular");
return value;
}
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
{
if (_parentAttribute === anAttribute)
return;
@@ -388,7 +548,7 @@ CPThemeStateCircular = CPThemeState("circular");
_parentAttribute = anAttribute;
}
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
{
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
@@ -473,15 +633,15 @@ CPThemeStateCircular = CPThemeState("circular");
@end
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
6 /*111111*/ ];
var numberOfOnes = function(aNumber)
@@ -552,7 +712,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
}
if (aTheme && aClass)
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
return attribute;
}
@@ -586,4 +746,4 @@ for (i = 0;i < Math.pow(2,6);++i)
}
print(str+']');
*/
*/
+30 -7
View File
@@ -33,37 +33,60 @@
@implementation CPThemeBlend : CPObject
{
CPBundle _bundle;
CPArray _themes @accessors(readonly, getter=themes);
CPArray _themes;
id _loadDelegate;
}
- (id)initWithContentsOfURL:(CPURL)aURL
{
self = [super init];
if (self)
{
_bundle = [[CPBundle alloc] initWithPath:aURL];
}
return self;
}
/*!
Returns an array of names of the keyed theme archives that make up this blend.
Each item in the array will have the extension ".keyedtheme".
*/
- (CPArray)themes
{
return _themes;
}
/*!
Returns an array of names of the themes that make up this blend.
*/
- (CPArray)themeNames
{
var names = [];
for (var i = 0; i < _themes.length; ++i)
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
return names;
}
- (void)loadWithDelegate:(id)aDelegate
{
_loadDelegate = aDelegate;
[_bundle loadWithDelegate:self];
}
- (void)bundleDidFinishLoading:(CPBundle)aBundle
{
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
count = themes.length;
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
var count = _themes.length;
while (count--)
{
var path = [aBundle pathForResource:themes[count]],
var path = [aBundle pathForResource:_themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle];
+7 -5
View File
@@ -563,6 +563,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO];
[[_additionalItemsButton menu] setAutoenablesItems:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
}
@@ -793,14 +794,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES;
[_additionalItemsButton addItemWithTitle:[item label]];
var menuItem = [_additionalItemsButton itemArray][index + 1];
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
[menuItem setImage:[item image]];
[menuItem setTarget:[item target]];
[menuItem setAction:[item action]];
[menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem];
}
}
else
@@ -1055,6 +1055,8 @@ var TOP_MARGIN = 5.0,
[_imageView setAlphaValue:0.5];
[_labelField setAlphaValue:0.5];
}
[_toolbar tile];
}
- (CPColor)FIXME_labelColor
+251 -183
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -79,9 +79,9 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary]
startFrame = [self _startFrame:dictionary]
endFrame = [self _endFrame:dictionary]
view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary],
endFrame = [self _endFrame:dictionary],
differenceFrame = _CGRectMakeZero();
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
+18 -6
View File
@@ -47,7 +47,8 @@ var CPViewControllerCachedCibs;
*/
@implementation CPViewController : CPResponder
{
CPView _view;
CPView _view @accessors(property=view);
BOOL _isLoading;
id _representedObject @accessors(property=representedObject);
CPString _title @accessors(property=title);
@@ -99,6 +100,8 @@ var CPViewControllerCachedCibs;
_cibName = aCibNameOrNil;
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
_isLoading = NO;
}
return self;
@@ -111,16 +114,16 @@ var CPViewControllerCachedCibs;
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
If you use Interface Builder to create your views, you initialize the view using the
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
Note: The cib loading system is currently asynchronous.
Note: The cib loading system is currently synchronous.
*/
- (void)loadView
{
if (_view)
return;
// check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
@@ -143,6 +146,8 @@ var CPViewControllerCachedCibs;
{
if (!_view)
{
_isLoading = YES;
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
@@ -163,6 +168,7 @@ var CPViewControllerCachedCibs;
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
[cibOwner viewControllerDidLoadCib:self];
_isLoading = NO;
[self viewDidLoad];
}
@@ -173,7 +179,7 @@ var CPViewControllerCachedCibs;
/*!
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
*/
- (void)viewDidLoad
{
@@ -189,7 +195,13 @@ var CPViewControllerCachedCibs;
*/
- (void)setView:(CPView)aView
{
var viewWasLoaded = !_view;
_view = aView;
// Make sure the viewDidLoad method is called if the view is set directly
if (!_isLoading && viewWasLoaded)
[self viewDidLoad];
}
@end
+46 -45
View File
@@ -50,23 +50,23 @@ CPWebViewScrollNative = 2;
{
CPScrollView _scrollView;
CPView _frameView;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
CPWebScriptObject _wso;
CPString _url;
CPString _html;
@@ -95,10 +95,10 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
[self _initDOMWithFrame:aFrame];
}
return self;
}
@@ -106,52 +106,52 @@ CPWebViewScrollNative = 2;
{
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
_iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.style.width = "100%";
_iframe.style.height = "100%";
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
_loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
// post the start load notification
[self _startedLoading];
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
}
else
_ignoreLoadStart = NO;
if (!_ignoreLoadEnd)
{
[self _finishedLoading];
}
else
_ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
@@ -159,9 +159,9 @@ CPWebViewScrollNative = 2;
[_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView];
_frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode];
[self addSubview:_scrollView];
@@ -169,7 +169,7 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize
{
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
@@ -211,7 +211,7 @@ CPWebViewScrollNative = 2;
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
@@ -229,7 +229,7 @@ CPWebViewScrollNative = 2;
else
{
CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)];
}
@@ -242,7 +242,7 @@ CPWebViewScrollNative = 2;
{
if (_scrollMode == aScrollMode)
return;
[self _setScrollMode:aScrollMode];
}
@@ -252,7 +252,7 @@ CPWebViewScrollNative = 2;
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
@@ -263,16 +263,16 @@ CPWebViewScrollNative = 2;
{
[_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no");
}
else
{
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "auto");
[_frameView setFrameSize:[_scrollView bounds].size];
}
@@ -293,13 +293,13 @@ CPWebViewScrollNative = 2;
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = null;
_html = aString;
[self _load];
}
@@ -308,13 +308,13 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
[self _load];
}
@@ -335,12 +335,13 @@ CPWebViewScrollNative = 2;
_loadHTMLStringTimer = nil;
}
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
_loadHTMLStringTimer = window.setTimeout(function()
{
var win = [self DOMWindow];
win.document.write(_html);
if (win)
win.document.write(_html);
window.setTimeout(_loadCallback, 1);
}, 0);
@@ -372,7 +373,7 @@ CPWebViewScrollNative = 2;
}
- (void)setMainFrameURL:(CPString)URLString
{
{
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = URLString;
@@ -389,9 +390,9 @@ CPWebViewScrollNative = 2;
[_forwardStack addObject:_mainFrameURL];
_mainFrameURL = [_backwardStack lastObject];
[_backwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -405,9 +406,9 @@ CPWebViewScrollNative = 2;
[_backwardStack addObject:_mainFrameURL];
_mainFrameURL = [_forwardStack lastObject];
[_forwardStack removeLastObject];
[self _loadMainFrameURL];
return YES;
}
return NO;
@@ -630,7 +631,7 @@ CPWebViewScrollNative = 2;
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// FIXME: encode/decode these?
@@ -638,14 +639,14 @@ CPWebViewScrollNative = 2;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
#if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]];
#endif
[self setBackgroundColor:[CPColor whiteColor]];
}
return self;
}
+79 -31
View File
@@ -200,6 +200,8 @@ var SHADOW_MARGIN_LEFT = 20.0,
var CPWindowSaveImage = nil,
CPWindowSavingImage = nil;
var CPWindowResizeTime = 0.2;
/*!
@ingroup appkit
@class CPWindow
@@ -320,6 +322,8 @@ var CPWindowSaveImage = nil,
CPDictionary _sheetContext;
CPWindow _parentView;
BOOL _isSheet;
_CPWindowFrameAnimation _frameAnimation;
}
/*
@@ -659,9 +663,10 @@ CPTexturedBackgroundWindowMask
if (shouldAnimate)
{
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[_frameAnimation stopAnimation];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[animation startAnimation];
[_frameAnimation startAnimation];
}
else
{
@@ -1359,10 +1364,21 @@ CPTexturedBackgroundWindowMask
*/
- (void)center
{
if (_isFullPlatformWindow)
return;
var size = [self frame].size,
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
[self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)];
var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
if (origin.x < 0.0)
origin.x = 0.0;
if (origin.y < 0.0)
origin.y = 0.0;
[self setFrameOrigin:origin];
}
/*!
@@ -1376,8 +1392,18 @@ CPTexturedBackgroundWindowMask
switch (type)
{
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
case CPKeyDown: [[self firstResponder] keyDown:anEvent];
// Trigger the default button if needed
if (![self disableKeyEquivalentForDefaultButton])
if ([anEvent _triggersKeyEquivalent:[[self defaultButton] keyEquivalent] withModifierMask:[[self defaultButton] keyEquivalentModifierMask]])
[[self defaultButton] performClick:self];
return;
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
@@ -1600,7 +1626,7 @@ CPTexturedBackgroundWindowMask
if (!pasteboardTypes)
return;
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
if ([_inclusiveRegisteredDraggedTypes count] === 0)
_inclusiveRegisteredDraggedTypes = nil;
@@ -1631,7 +1657,7 @@ CPTexturedBackgroundWindowMask
return;
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
_registeredDraggedTypesArray = nil;
@@ -1644,7 +1670,7 @@ CPTexturedBackgroundWindowMask
- (CPArray)registeredDraggedTypes
{
if (!_registeredDraggedTypesArray)
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
return _registeredDraggedTypesArray;
}
@@ -1942,10 +1968,16 @@ CPTexturedBackgroundWindowMask
else
{
var mainMenu = [CPApp mainMenu],
menuWindow = mainMenu ? mainMenu._menuWindow : nil;
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++)
{
var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow)
continue;
@@ -1971,10 +2003,16 @@ CPTexturedBackgroundWindowMask
else
{
var mainMenu = [CPApp mainMenu],
menuWindow = mainMenu ? mainMenu._menuWindow : nil;
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++)
{
var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow)
continue;
@@ -2054,11 +2092,17 @@ CPTexturedBackgroundWindowMask
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
{
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[animation setDelegate:delegate];
[animation setAnimationCurve:curve];
[animation setDuration:duration];
[animation startAnimation];
[_frameAnimation stopAnimation];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[_frameAnimation setDelegate:delegate];
[_frameAnimation setAnimationCurve:curve];
[_frameAnimation setDuration:duration];
[_frameAnimation startAnimation];
}
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
{
return CPWindowResizeTime;
}
/* @ignore */
@@ -2109,7 +2153,7 @@ CPTexturedBackgroundWindowMask
[aSheet setFrame:startFrame display:YES animate:NO];
_sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
[aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
// Should run the main loop here until _isAnimating = FALSE
[aSheet becomeKeyWindow];
@@ -2130,7 +2174,7 @@ CPTexturedBackgroundWindowMask
[self _setUpMasksForView:sheetContent];
_sheetContext["opened"] = NO;
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
[sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
}
/* @ignore */
@@ -2159,13 +2203,15 @@ CPTexturedBackgroundWindowMask
[self _restoreMasksForView:sheetContent];
var delegate = _sheetContext["modalDelegate"],
endSelector = _sheetContext["endSelector"];
if (delegate != nil && endSelector != nil)
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
endSelector = _sheetContext["endSelector"],
returnCode = _sheetContext["returnCode"],
contextInfo = _sheetContext["contextInfo"];
_sheetContext = nil;
sheet._parentView = nil;
if (delegate != nil && endSelector != nil)
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
}
- (void)_setUpMasksForView:(CPView)aView
@@ -2238,7 +2284,7 @@ CPTexturedBackgroundWindowMask
return NO;
}
- (void)performKeyEquivalent:(CPEvent)anEvent
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
// FIXME: should we be starting at the root, in other words _windowView?
// The evidence seems to point to no...
@@ -2249,14 +2295,11 @@ CPTexturedBackgroundWindowMask
{
// It's not clear why we do performKeyEquivalent again here...
// Perhaps to allow something to happen between sendEvent: and keyDown:?
if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent])
[self interpretKeyEvents:[anEvent]];
}
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
return;
- (void)insertNewline:(id)sender
{
if (_defaultButton && _defaultButtonEnabled)
[_defaultButton performClick:nil];
// Interpret the key events
[self interpretKeyEvents:[anEvent]];
}
- (void)insertTab:(id)sender
@@ -2369,11 +2412,16 @@ CPTexturedBackgroundWindowMask
- (void)setDefaultButton:(CPButton)aButton
{
[_defaultButton setDefaultButton:NO];
if (_defaultButton === aButton)
return;
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:nil];
_defaultButton = aButton;
[_defaultButton setDefaultButton:YES];
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
}
- (CPButton)defaultButton
@@ -2634,7 +2682,7 @@ var interpolate = function(fromValue, toValue, progress)
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
{
self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear];
self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
if (self)
{
+12 -12
View File
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)]
]]];
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)];
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)];
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)];
}
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{
var closeSize = [_CPHUDWindowViewCloseImage size];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)];
[_closeButton setBordered:NO];
+2 -2
View File
@@ -133,7 +133,7 @@
if (_window)
return;
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
}
/*!
@@ -424,7 +424,7 @@
if (_windowCibPath)
return _windowCibPath;
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
}
// Setting and Getting Window Attributes
+1 -1
View File
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects];
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
+9 -3
View File
@@ -39,9 +39,11 @@
// Not having a selector is a fatal error.
if (!selector)
{
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
}
// If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector])
@@ -58,7 +60,7 @@
else
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setAction:"];
// Not being able to set the target is a fatal error.
if ([_source respondsToSelector:@selector(setTarget:)])
@@ -67,10 +69,14 @@
else
[CPException
raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setTarget:"];
}
@end
@implementation _CPCibControlConnector : CPCibControlConnector { } @end
@implementation _CPCibControlConnector : CPCibControlConnector
{
}
@end
+15 -5
View File
@@ -46,28 +46,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
{
self = [super init];
if (self)
{
_className = aClassName;
_resourceName = aResourceName;
_properties = properties;
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
}
return self;
}
@@ -80,7 +80,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)awakeAfterUsingCoder:(CPCoder)aCoder
{
if ([aCoder respondsToSelector:@selector(bundle)] &&
if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage")
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
@@ -112,4 +112,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
return NO;
}
- (unsigned)loadStatus
{
return CPImageLoadStatusCompleted;
}
- (id)delegate
{
return nil;
}
@end
+1
View File
@@ -63,6 +63,7 @@
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
#define _CGInsetEqualToInset(lhsInset, rhsInset) ((lhsInset).top === (rhsInset).top && (lhsInset).right === (rhsInset).right && (lhsInset).bottom === (rhsInset).bottom && (lhsInset).left === (rhsInset).left)
// DEPRECATED
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
+65 -15
View File
@@ -69,6 +69,12 @@ _function(CGInsetMake(top, right, bottom, left))
_function(CGInsetMakeZero())
_function(CGInsetMakeCopy(anInset))
_function(CGInsetIsEmpty(anInset))
_function(CGInsetEqualToInset(lhsInset, rhsInset))
CGMinXEdge = 0;
CGMinYEdge = 1;
CGMaxXEdge = 2;
CGMaxYEdge = 3;
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
@@ -77,6 +83,50 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
@{
*/
/*!
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
with a line that's parallel to the side of inRect specified by edge.
The size of slice is determined by amount, which specifies the distance from edge.
slice and rem must not be NULL, must not be the same object, and must not be the
same object as inRect.
@group CGRect
*/
function CGRectDivide(inRect, slice, rem, amount, edge)
{
slice.origin = _CGPointMakeCopy(inRect.origin);
slice.size = _CGSizeMakeCopy(inRect.size);
rem.origin = _CGPointMakeCopy(inRect.origin);
rem.size = _CGSizeMakeCopy(inRect.size);
switch (edge)
{
case CGMinXEdge:
slice.size.width = amount;
rem.origin.x += amount;
rem.size.width -= amount;
break;
case CGMaxXEdge:
slice.origin.x = _CGRectGetMaxX(slice) - amount;
slice.size.width = amount;
rem.size.width -= amount;
break;
case CGMinYEdge:
slice.size.height = amount;
rem.origin.y += amount;
rem.size.height -= amount;
break;
case CGMaxYEdge:
slice.origin.y = _CGRectGetMaxY(slice) - amount;
slice.size.height = amount;
rem.size.height -= amount;
}
}
/*!
Returns a \c BOOL indicating whether CGRect \c lhsRect
contains CGRect \c rhsRect.
@@ -88,7 +138,7 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
function CGRectContainsRect(lhsRect, rhsRect)
{
var union = CGRectUnion(lhsRect, rhsRect);
return _CGRectEqualToRect(union, lhsRect);
}
@@ -102,12 +152,12 @@ function CGRectContainsRect(lhsRect, rhsRect)
function CGRectIntersectsRect(lhsRect, rhsRect)
{
var intersection = CGRectIntersection(lhsRect, rhsRect);
return !_CGRectIsEmpty(intersection);
}
/*!
Makes the origin and size of a CGRect all integers. Specifically, by making
Makes the origin and size of a CGRect all integers. Specifically, by making
the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up).
@param aRect the rectangle to operate on
@return CGRect the modified rectangle (same as the input)
@@ -120,7 +170,7 @@ function CGRectIntegral(aRect)
// Store these out separately, if not the GetMaxes will return incorrect values.
var x = FLOOR(_CGRectGetMinX(aRect)),
y = FLOOR(_CGRectGetMinY(aRect));
aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x;
aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y;
@@ -140,18 +190,18 @@ function CGRectIntegral(aRect)
function CGRectIntersection(lhsRect, rhsRect)
{
var intersection = _CGRectMake(
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
0, 0);
intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection);
intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection);
return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection;
}
/*
*/
function CGRectStandardize(aRect)
{
@@ -189,28 +239,28 @@ function CGRectUnion(lhsRect, rhsRect)
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect));
return _CGRectMake(minX, minY, maxX - minX, maxY - minY);
}
function CGPointFromString(aString)
{
var comma = aString.indexOf(',');
return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) };
}
function CGSizeFromString(aString)
{
var comma = aString.indexOf(',');
return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) };
}
function CGRectFromString(aString)
{
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) };
}
@@ -233,6 +283,6 @@ function CPStringFromCGInset(anInset)
return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}';
}
/*!
@}
/*!
@}
*/
+2
View File
@@ -42,6 +42,8 @@ var PrimaryPlatformWindow = NULL;
DOMElement _DOMBodyElement;
DOMElement _DOMFocusElement;
DOMElement _DOMEventGuard;
DOMElement _DOMScrollingElement;
id _hideDOMScrollingElementTimeout;
CPArray _windowLevels;
CPDictionary _windowLayers;
+69 -1
View File
@@ -24,7 +24,11 @@
var DOMFixedWidthSpanElement = nil,
DOMFlexibleWidthSpanElement = nil,
DOMMetricsDivElement = nil,
DOMMetricsTextSpanElement = nil,
DOMMetricsImgElement = nil,
DOMIFrameElement = nil,
DOMIFrameDocument = nil,
DefaultFont = nil;
@implementation CPPlatformString : CPBasePlatformString
@@ -59,7 +63,7 @@ var DOMFixedWidthSpanElement = nil,
bodyElement.appendChild(DOMIFrameElement);
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
DOMIFrameDocument.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head></head><body></body></html>');
DOMIFrameDocument.close();
@@ -88,6 +92,7 @@ var DOMFixedWidthSpanElement = nil,
style.margin = "0px";
style.width = "1px";
style.wordWrap = "break-word";
try
{
style.whiteSpace = "pre";
@@ -106,6 +111,46 @@ var DOMFixedWidthSpanElement = nil,
DOMDivElement.appendChild(DOMFixedWidthSpanElement);
}
+ (void)createDOMMetricsElements
{
if (!DOMIFrameElement)
[self createDOMElements];
var style;
DOMMetricsDivElement = DOMIFrameDocument.createElement("div");
DOMMetricsDivElement.style.position = "absolute";
DOMMetricsDivElement.style.width = "100000px";
DOMIFrameDocument.body.appendChild(DOMMetricsDivElement);
DOMMetricsTextSpanElement = DOMIFrameDocument.createElement("span");
DOMMetricsTextSpanElement.innerHTML = "x";
style = DOMMetricsTextSpanElement.style;
style.position = "absolute";
style.visibility = "visible";
style.padding = "0px";
style.margin = "0px";
style.whiteSpace = "pre";
var imgPath = [[CPBundle bundleForClass:[CPView class]] pathForResource:@"empty.png"];
DOMMetricsImgElement = DOMIFrameDocument.createElement("img");
DOMMetricsImgElement.setAttribute("src", imgPath);
DOMMetricsImgElement.setAttribute("width", "1");
DOMMetricsImgElement.setAttribute("height", "1");
DOMMetricsImgElement.setAttribute("alt", "");
style = DOMMetricsImgElement.style;
style.visibility = "visible";
style.padding = "0px";
style.margin = "0px";
style.border = "none";
style.verticalAlign = "baseline";
DOMMetricsDivElement.appendChild(DOMMetricsTextSpanElement);
DOMMetricsDivElement.appendChild(DOMMetricsImgElement);
}
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
{
if (!aFont)
@@ -120,6 +165,7 @@ var DOMFixedWidthSpanElement = nil,
[self createDOMElements];
var span;
if (!aWidth)
span = DOMFlexibleWidthSpanElement;
else
@@ -138,4 +184,26 @@ var DOMFixedWidthSpanElement = nil,
return _CGSizeMake(span.clientWidth, span.clientHeight);
}
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
if (!aFont)
{
if (!DefaultFont)
DefaultFont = [CPFont systemFontOfSize:12.0];
aFont = DefaultFont;
}
if (!DOMMetricsDivElement)
[self createDOMMetricsElements];
DOMMetricsDivElement.style.font = [aFont cssString];
var baseline = DOMMetricsImgElement.offsetTop - DOMMetricsTextSpanElement.offsetTop + DOMMetricsImgElement.offsetHeight,
descender = baseline - DOMMetricsTextSpanElement.offsetHeight,
lineHeight = DOMMetricsTextSpanElement.offsetHeight;
return [CPDictionary dictionaryWithObjectsAndKeys:baseline, @"ascender", descender, @"descender", lineHeight, @"lineHeight"];
}
@end
+207 -76
View File
@@ -136,25 +136,58 @@ var CPDOMEventGetClickCount,
//might be mac only, we should investigate futher later.
var KeyCodesToPrevent = {},
CharacterKeysToPrevent = {},
KeyCodesToAllow = {},
MozKeyCodeToKeyCodeMap = {
61: 187, // =, equals
59: 186 // ;, semicolon
},
KeyCodesToFunctionUnicodeMap = {};
KeyCodesToUnicodeMap = {};
KeyCodesToPrevent[CPKeyCodes.A] = YES;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPBackspaceCharacter;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteCharacter;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey;
KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey;
KeyCodesToAllow[CPKeyCodes.F1] = YES;
KeyCodesToAllow[CPKeyCodes.F2] = YES;
KeyCodesToAllow[CPKeyCodes.F3] = YES;
KeyCodesToAllow[CPKeyCodes.F4] = YES;
KeyCodesToAllow[CPKeyCodes.F5] = YES;
KeyCodesToAllow[CPKeyCodes.F6] = YES;
KeyCodesToAllow[CPKeyCodes.F7] = YES;
KeyCodesToAllow[CPKeyCodes.F8] = YES;
KeyCodesToAllow[CPKeyCodes.F9] = YES;
KeyCodesToAllow[CPKeyCodes.F10] = YES;
KeyCodesToAllow[CPKeyCodes.F11] = YES;
KeyCodesToAllow[CPKeyCodes.F12] = YES;
KeyCodesToUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter;
KeyCodesToUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter;
KeyCodesToUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter;
KeyCodesToUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey;
KeyCodesToUnicodeMap[CPKeyCodes.SEMICOLON] = ";";
KeyCodesToUnicodeMap[CPKeyCodes.DASH] = "-";
KeyCodesToUnicodeMap[CPKeyCodes.EQUALS] = "=";
KeyCodesToUnicodeMap[CPKeyCodes.COMMA] = ",";
KeyCodesToUnicodeMap[CPKeyCodes.PERIOD] = ".";
KeyCodesToUnicodeMap[CPKeyCodes.SLASH] = "/";
KeyCodesToUnicodeMap[CPKeyCodes.APOSTROPHE] = "`";
KeyCodesToUnicodeMap[CPKeyCodes.SINGLE_QUOTE] = "'";
KeyCodesToUnicodeMap[CPKeyCodes.OPEN_SQUARE_BRACKET] = "[";
KeyCodesToUnicodeMap[CPKeyCodes.BACKSLASH] = "\\";
KeyCodesToUnicodeMap[CPKeyCodes.CLOSE_SQUARE_BRACKET] = "]";
var ModifierKeyCodes = [
CPKeyCodes.META,
CPKeyCodes.MAC_FF_META,
CPKeyCodes.CTRL,
CPKeyCodes.ALT,
CPKeyCodes.SHIFT
];
var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
@@ -283,6 +316,29 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMEventGuard.style.display = "none";
_DOMEventGuard.className = "cpdontremove";
_DOMBodyElement.appendChild(_DOMEventGuard);
// We get scrolling deltas from this element
_DOMScrollingElement = theDocument.createElement("div");
_DOMScrollingElement.style.position = "absolute";
_DOMScrollingElement.style.visibility = "hidden";
_DOMScrollingElement.style.zIndex = "998";
_DOMScrollingElement.style.height = "60px";
_DOMScrollingElement.style.width = "60px";
_DOMScrollingElement.style.overflow = "scroll";
//_DOMScrollingElement.style.backgroundColor = "rgba(0,0,0,1.0)"; // debug help.
_DOMScrollingElement.style.opacity = "0";
_DOMScrollingElement.style.filter = "alpha(opacity=0)";
_DOMScrollingElement.className = "cpdontremove";
_DOMBodyElement.appendChild(_DOMScrollingElement);
var _DOMInnerScrollingElement = theDocument.createElement("div");
_DOMInnerScrollingElement.style.width = "400px";
_DOMInnerScrollingElement.style.height = "400px";
_DOMScrollingElement.appendChild(_DOMInnerScrollingElement);
// Set an initial scroll offset
_DOMScrollingElement.scrollTop = 150;
_DOMScrollingElement.scrollLeft = 150;
}
- (void)registerDOMWindow
@@ -542,7 +598,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
[dragServer draggingStartedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
}
else if (type === "drag")
{
var y = aDOMEvent.screenY;
@@ -552,7 +607,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
[dragServer draggingSourceUpdatedWithGlobalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, y)];
}
else if (type === "dragover" || type === "dragleave")
{
if (aDOMEvent.preventDefault)
@@ -563,16 +617,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (dragOperation === CPDragOperationMove || dragOperation === CPDragOperationGeneric || dragOperation === CPDragOperationPrivate)
dropEffect = "move";
else if (dragOperation === CPDragOperationCopy)
dropEffect = "copy";
else if (dragOperation === CPDragOperationLink)
dropEffect = "link";
aDOMEvent.dataTransfer.dropEffect = dropEffect;
}
else if (type === "dragend")
{
var dropEffect = aDOMEvent.dataTransfer.dropEffect;
@@ -588,7 +639,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
[dragServer draggingEndedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY) operation:dragOperation];
}
else //if (type === "drop")
{
[dragServer performDragOperationInPlatformWindow:self];
@@ -607,18 +657,37 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
- (void)keyEvent:(DOMEvent)aDOMEvent
{
var event,
timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
timestamp = aDOMEvent.timeStamp || new Date(),
sourceElement = aDOMEvent.target || aDOMEvent.srcElement,
windowNumber = [[CPApp keyWindow] windowNumber],
modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
KeyCodesToPrevent[aDOMEvent.keyCode]);
// With a few exceptions, all key events are blocked from propagating to
// the browser. Here the following exceptions are being allowed:
//
// - All keys pressed along with a ctrl or cmd key _unless_ they are in
// one of the two blacklists.
// - Any key listed in the whitelist.
//
// The ctrl/cmd keys are used for browser hotkeys as are the keys listed in
// the whitelist (F1-F12 at the time of writing).
//
// If a key is listed in both the blacklist and whitelist, the blacklist is
// checked first. The key will be blocked from propagating in that case.
StopDOMEventPropagation = YES;
// Make sure it is not in the blacklists.
if (!(CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || KeyCodesToPrevent[aDOMEvent.keyCode]))
{
// It is not in the blacklist, let it through if the ctrl/cmd key is
// also down or it's in the whitelist.
if ((modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || KeyCodesToAllow[aDOMEvent.keyCode])
StopDOMEventPropagation = NO;
}
var isNativePasteEvent = NO,
isNativeCopyOrCutEvent = NO,
@@ -627,19 +696,36 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
switch (aDOMEvent.type)
{
case "keydown": // Grab and store the keycode now since it is correct and consistent at this point.
if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap)
if (aDOMEvent.keyCode in MozKeyCodeToKeyCodeMap)
_keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode];
else
_keyCode = aDOMEvent.keyCode;
var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase();
var characters;
// Handle key codes for which String.fromCharCode won't work.
if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)
characters = KeyCodesToUnicodeMap[_keyCode];
if (!characters)
characters = String.fromCharCode(_keyCode).toLowerCase();
overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters;
// check for caps lock state
if (_keyCode === CPKeyCodes.CAPS_LOCK)
_capsLockActive = YES;
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
if ([ModifierKeyCodes containsObject:_keyCode])
{
// A modifier key will never fire keypress. We don't need to do any other processing so we just fire it here and break.
event = [CPEvent keyEventWithType:CPFlagsChanged location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil
characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:_keyCode];
break;
}
else if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
{
//we are simply going to skip all keypress events that use cmd/ctrl key
//this lets us be consistent in all browsers and send on the keydown
@@ -696,8 +782,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_lastKey = keyCode;
_charCodes[keyCode] = charCode;
var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode),
charactersIgnoringModifiers = characters.toLowerCase();
var characters = overrideCharacters;
// Is this a special key?
if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0))
characters = KeyCodesToUnicodeMap[charCode];
if (!characters)
characters = String.fromCharCode(charCode);
charactersIgnoringModifiers = characters.toLowerCase(); // FIXME: This isn't correct. It SHOULD include Shift.
// Safari won't send proper capitalization during cmd-key events
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive))
@@ -705,7 +798,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode];
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:charCode];
if (isNativePasteEvent)
{
@@ -728,7 +821,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (keyCode === CPKeyCodes.CAPS_LOCK)
_capsLockActive = NO;
var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode),
if ([ModifierKeyCodes containsObject:keyCode])
break;
var characters = KeyCodesToUnicodeMap[charCode] || String.fromCharCode(charCode),
charactersIgnoringModifiers = characters.toLowerCase();
if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive)
@@ -862,7 +958,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
- (void)scrollEvent:(DOMEvent)aDOMEvent
{
if(!aDOMEvent)
if (_hideDOMScrollingElementTimeout)
{
clearTimeout(_hideDOMScrollingElementTimeout);
_hideDOMScrollingElementTimeout = nil;
}
if (!aDOMEvent)
aDOMEvent = window.event;
var location = nil;
@@ -881,7 +983,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
{
x += element.offsetLeft;
y += element.offsetTop;
} while (element = element.offsetParent);
}
@@ -901,7 +1002,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
StopDOMEventPropagation = YES;
// Show the dom element
_DOMScrollingElement.style.visibility = "visible";
_DOMScrollingElement.style.top = (location.y - 15) + @"px";
_DOMScrollingElement.style.left = (location.x - 15) + @"px";
// We let the browser handle the scrolling
StopDOMEventPropagation = NO;
var theWindow = [self hitTest:location];
@@ -912,40 +1019,54 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
location = [theWindow convertBridgeToBase:location];
if(typeof aDOMEvent.wheelDeltaX != "undefined")
{
deltaX = aDOMEvent.wheelDeltaX / 120.0;
deltaY = aDOMEvent.wheelDeltaY / 120.0;
}
else if (aDOMEvent.wheelDelta)
deltaY = aDOMEvent.wheelDelta / 120.0;
else if (aDOMEvent.detail)
deltaY = -aDOMEvent.detail / 3.0;
else
return;
if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues))
{
deltaX = -deltaX;
deltaY = -deltaY;
}
var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ];
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
event._DOMEvent = aDOMEvent;
event._deltaX = deltaX;
event._deltaY = deltaY;
[CPApp sendEvent:event];
// We lag 1 event behind without this timeout.
setTimeout(function()
{
// Find the scroll delta
var deltaX = _DOMScrollingElement.scrollLeft - 150,
deltaY = _DOMScrollingElement.scrollTop - 150;
if (StopDOMEventPropagation)
CPDOMEventStop(aDOMEvent, self);
// If we scroll super with momentum,
// there are so many events going off that
// a tiny percent don't actually have any deltas.
//
// This does *not* make scrolling appear sluggish,
// it just seems like that is something that happens.
//
// We get free performance boost if we skip sending these events,
// as sending a scroll event with no deltas doesn't do anything.
if (deltaX || deltaY)
{
event._deltaX = deltaX;
event._deltaY = deltaY;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[CPApp sendEvent:event];
}
// We set StopDOMEventPropagation = NO on line 1008
//if (StopDOMEventPropagation)
// CPDOMEventStop(aDOMEvent, self);
// Reset the DOM elements scroll offset
_DOMScrollingElement.scrollLeft = 150;
_DOMScrollingElement.scrollTop = 150;
// Is this needed?
//[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}, 0);
// We hide the dom element after a little bit
// so that other DOM elements such as inputs
// can receive events.
_hideDOMScrollingElementTimeout = setTimeout(function()
{
_DOMScrollingElement.style.visibility = "hidden";
}, 300);
}
- (void)resizeEvent:(DOMEvent)aDOMEvent
@@ -1007,8 +1128,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
newEvent.preventDefault = function() { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault() };
newEvent.stopPropagation = function() { if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation() };
[self mouseEvent:newEvent];
@@ -1057,7 +1178,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (_mouseDownWindow)
windowNumber = [_mouseDownWindow windowNumber];
else
{
var theWindow = [self hitTest:location];
@@ -1073,7 +1193,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (type === "mouseup")
{
if(_mouseIsDown)
if (_mouseIsDown)
{
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
@@ -1083,7 +1203,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_mouseDownIsRightClick = NO;
}
if(_DOMEventMode)
if (_DOMEventMode)
{
_DOMEventMode = NO;
return;
@@ -1092,6 +1212,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
else if (type === "mousedown")
{
var button = aDOMEvent.button;
_mouseDownIsRightClick = button == 2 || (CPBrowserIsOperatingSystem(CPMacOperatingSystem) && button == 0 && modifierFlags & CPControlKeyMask);
if (sourceElement.tagName === "INPUT" && sourceElement != _DOMFocusElement)
{
if ([CPPlatform supportsDragAndDrop])
@@ -1104,11 +1227,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_mouseIsDown = YES;
//fake a down and up event so that event tracking mode will work correctly
[CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags
[CPApp sendEvent:[CPEvent mouseEventWithType:_mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
[CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags
[CPApp sendEvent:[CPEvent mouseEventWithType:_mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
@@ -1120,9 +1243,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMBodyElement.style["-khtml-user-drag"] = "element";
}
var button = aDOMEvent.button;
_mouseDownIsRightClick = button == 2 || (button == 0 && modifierFlags & CPControlKeyMask);
StopContextMenuDOMEventPropagation = YES;
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
@@ -1152,7 +1272,18 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
CPDOMEventStop(aDOMEvent, self);
// if there are any tracking event listeners then show the event guard so we don't lose events to iframes
_DOMEventGuard.style.display = (CPApp._eventListeners.length === 0) ? "none" : "";
// TODO Actually check for tracking event listeners, not just any listener but _CPRunModalLoop.
var hasTrackingEventListener = NO;
for (var i=0; i < CPApp._eventListeners.length; i++)
{
if (CPApp._eventListeners[i]._callback !== _CPRunModalLoop)
{
hasTrackingEventListener = YES;
break;
}
}
_DOMEventGuard.style.display = hasTrackingEventListener ? "" : "none";
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
@@ -1356,7 +1487,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
*/
+ (void)preventCharacterKeysFromPropagating:(CPArray)characters
{
for(var i=characters.length; i>0; i--)
for (var i = characters.length; i > 0; i--)
CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES;
}
@@ -1382,7 +1513,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
*/
+ (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
{
for(var i=keyCodes.length; i>0; i--)
for (var i = keyCodes.length; i > 0; i--)
KeyCodesToPrevent[keyCodes[i-1]] = YES;
}
-58
View File
@@ -1,58 +0,0 @@
These graphics come from the Tango Desktop Project (http://tango.freedesktop.org/Tango_Desktop_Project).
They are released under the Creative Commons Attribution Share-Alike license, full text below.
(license available from CC here: http://creativecommons.org/licenses/by-sa/2.5/)
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
"Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
"Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
"Licensor" means the individual or entity that offers the Work under the terms of this License.
"Original Author" means the individual or entity who created the Work.
"Work" means the copyrightable work of authorship offered under the terms of this License.
"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
to create and reproduce Derivative Works;
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
For the avoidance of doubt, where the work is a musical composition:
Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. Termination
This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
8. Miscellaneous
Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 B

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 B

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

After

Width:  |  Height:  |  Size: 1002 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 B

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 B

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

After

Width:  |  Height:  |  Size: 1019 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 349 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 283 B

After

Width:  |  Height:  |  Size: 283 B

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before

Width:  |  Height:  |  Size: 424 B

After

Width:  |  Height:  |  Size: 424 B

Before

Width:  |  Height:  |  Size: 419 B

After

Width:  |  Height:  |  Size: 419 B

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

Before

Width:  |  Height:  |  Size: 639 B

After

Width:  |  Height:  |  Size: 639 B

Before

Width:  |  Height:  |  Size: 625 B

After

Width:  |  Height:  |  Size: 625 B

Before

Width:  |  Height:  |  Size: 617 B

After

Width:  |  Height:  |  Size: 617 B

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 269 B

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 653 B

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 657 B

Before

Width:  |  Height:  |  Size: 841 B

After

Width:  |  Height:  |  Size: 841 B

Some files were not shown because too many files have changed in this diff Show More